diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py
index 6371085..237cb32 100644
--- a/web/pgAdmin4.py
+++ b/web/pgAdmin4.py
@@ -7,7 +7,7 @@
 #
 ##########################################################################
 
-"""This is the main application entry point for pgAdmin 4. If running on 
+"""This is the main application entry point for pgAdmin 4. If running on
 a webserver, this will provide the WSGI interface, otherwise, we're going
 to start a web server."""
 
@@ -50,8 +50,11 @@ if not os.path.isfile(config.SQLITE_PATH):
 # Create the app!
 app = create_app()
 
+if config.DEBUG:
+    app.debug = True
+
 # Start the web server. The port number should have already been set by the
-# runtime if we're running in desktop mode, otherwise we'll just use the 
+# runtime if we're running in desktop mode, otherwise we'll just use the
 # Flask default.
 if 'PGADMIN_PORT' in globals():
     app.logger.debug('PGADMIN_PORT set in the runtime environment to %s', PGADMIN_PORT)
@@ -64,4 +67,3 @@ try:
     app.run(port=server_port)
 except IOError:
     app.logger.error("Error starting the app server: %s", sys.exc_info())
-
diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index ee8bc12..efd4b7c 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -9,28 +9,77 @@
 
 """The main pgAdmin module. This handles the application initialisation tasks,
 such as setup of logging, dynamic loading of modules etc."""
-
-from flask import Flask, abort, request
+from collections import defaultdict
+from flask import Flask, abort, request, current_app
 from flask.ext.babel import Babel
-from flask.ext.sqlalchemy import SQLAlchemy
-from flask.ext.security import Security, SQLAlchemyUserDatastore, login_required
+from flask.ext.security import Security, SQLAlchemyUserDatastore
 from flask_security.utils import login_user
 from flask_mail import Mail
 from htmlmin.minify import html_minify
 from settings.settings_model import db, Role, User
-
-import inspect, imp, logging, os, sys
+from importlib import import_module
+from werkzeug.local import LocalProxy
+from pgadmin.utils import PgAdminModule
+from werkzeug.utils import find_modules
+import sys
+import logging
 
 # Configuration settings
 import config
 
-# Global module list
-modules = [ ]
+
+class PgAdmin(Flask):
+
+    def find_submodules(self, basemodule):
+        for module_name in find_modules(basemodule, True):
+            if module_name in self.config['MODULE_BLACKLIST']:
+                self.logger.info('Skipping blacklisted module: %s' %
+                                module_name)
+                continue
+            self.logger.info('Examining potential module: %s' % module_name)
+            module = import_module(module_name)
+            for key, value in module.__dict__.items():
+                if isinstance(value, PgAdminModule):
+                    yield value
+
+    @property
+    def submodules(self):
+        for blueprint in self.blueprints.values():
+            if isinstance(blueprint, PgAdminModule):
+                yield blueprint
+
+    @property
+    def stylesheets(self):
+        stylesheets = []
+        for module in self.submodules:
+            stylesheets.extend(getattr(module, "stylesheets", []))
+        return stylesheets
+
+    @property
+    def javascripts(self):
+        stylesheets = []
+        for module in self.submodules:
+            stylesheets.extend(getattr(module, "javascripts", []))
+        return stylesheets
+
+    @property
+    def panels(self):
+        panels = []
+        for module in self.submodules:
+            panels.extend(module.get_panels())
+        return panels
+
+def _find_blueprint():
+    if request.blueprint:
+        return current_app.blueprints[request.blueprint]
+
+current_blueprint = LocalProxy(_find_blueprint)
+
 
 def create_app(app_name=config.APP_NAME):
     """Create the Flask application, startup logging and dynamically load
     additional modules (blueprints) that are found in this directory."""
-    app = Flask(__name__, static_url_path='/static')
+    app = PgAdmin(__name__, static_url_path='/static')
     app.config.from_object(config)
 
     ##########################################################################
@@ -42,7 +91,7 @@ def create_app(app_name=config.APP_NAME):
     app.logger.setLevel(logging.DEBUG)
     app.logger.handlers = []
 
-    # We also need to update the handler on the webserver in order to see request. 
+    # We also need to update the handler on the webserver in order to see request.
     # Setting the level prevents werkzeug from setting up it's own stream handler
     # thus ensuring all the logging goes through the pgAdmin logger.
     logger = logging.getLogger('werkzeug')
@@ -67,82 +116,48 @@ def create_app(app_name=config.APP_NAME):
     app.logger.info('Starting %s v%s...', config.APP_NAME, config.APP_VERSION)
     app.logger.info('################################################################################')
     app.logger.debug("Python syspath: %s", sys.path)
-    
+
     ##########################################################################
     # Setup i18n
     ##########################################################################
-    
+
     # Initialise i18n
     babel = Babel(app)
-    
+
     app.logger.debug('Available translations: %s' % babel.list_translations())
 
     @babel.localeselector
     def get_locale():
         """Get the best language for the user."""
         language = request.accept_languages.best_match(config.LANGUAGES.keys())
-        return language 
+        return language
 
     ##########################################################################
     # Setup authentication
     ##########################################################################
-   
+
     app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + config.SQLITE_PATH.replace('\\', '/')
 
     # Only enable password related functionality in server mode.
-    if config.SERVER_MODE == True:
+    if config.SERVER_MODE is True:
         # TODO: Figure out how to disable /logout and /login
         app.config['SECURITY_RECOVERABLE'] = True
         app.config['SECURITY_CHANGEABLE'] = True
 
     # Create database connection object and mailer
     db.init_app(app)
-    mail = Mail(app)
+    Mail(app)
 
     # Setup Flask-Security
     user_datastore = SQLAlchemyUserDatastore(db, User, Role)
-    security = Security(app, user_datastore)
+    Security(app, user_datastore)
 
     ##########################################################################
     # Load plugin modules
     ##########################################################################
-
-    path = os.path.dirname(os.path.realpath(__file__))
-    files = os.listdir(path)
-
-    for f in files:
-        d = os.path.join(path, f)
-        if os.path.isdir(d) and os.path.isfile(os.path.join(d, '__init__.py')):
-
-            if f in config.MODULE_BLACKLIST:
-                app.logger.info('Skipping blacklisted module: %s' % f)
-                continue
-
-            # Construct the "real" module name
-            f = 'pgadmin.' + f
-            
-            # Looks like a module, so import it, and register the blueprint if present
-            # We rely on the ordering of syspath to ensure we actually get the right
-            # module here. Note that we also try to load the 'hooks' module for
-            # the browser integration hooks and other similar functions.
-            app.logger.info('Examining potential module: %s' % d)
-            module = __import__(f, globals(), locals(), ['hooks', 'views'], -1)
-
-            # Add the module to the global module list
-            modules.append(module)
-            
-            # Register the blueprint if present
-            if 'views' in dir(module) and 'blueprint' in dir(module.views):
-                app.logger.info('Registering blueprint module: %s' % f)
-                app.register_blueprint(module.views.blueprint)
-                app.logger.debug('   - root_path:       %s' % module.views.blueprint.root_path)
-                app.logger.debug('   - static_folder:   %s' % module.views.blueprint.static_folder)
-                app.logger.debug('   - template_folder: %s' % module.views.blueprint.template_folder)
-                
-            # Register any sub-modules
-            if 'hooks' in dir(module) and 'register_submodules' in dir(module.hooks):
-                app.logger.info('Registering sub-modules in %s' % f)
-                module.hooks.register_submodules(app)
+    for module in app.find_submodules('pgadmin'):
+        app.logger.info('Registering blueprint module: %s' % module)
+        app.register_blueprint(module)
 
     ##########################################################################
     # Handle the desktop login
@@ -151,7 +166,7 @@ def create_app(app_name=config.APP_NAME):
     @app.before_request
     def before_request():
         """Login the default user if running in desktop mode"""
-        if config.SERVER_MODE == False:
+        if config.SERVER_MODE is False:
             user = user_datastore.get_user(config.DESKTOP_USER)
 
             # Throw an error if we failed to find the desktop user, to give
@@ -165,7 +180,7 @@ def create_app(app_name=config.APP_NAME):
 
     ##########################################################################
     # Minify output
-    ##########################################################################    
+    ##########################################################################
     @app.after_request
     def response_minify(response):
         """Minify html response to decrease traffic"""
@@ -177,10 +192,20 @@ def create_app(app_name=config.APP_NAME):
 
         return response
 
+    @app.context_processor
+    def inject_blueprint():
+        """Inject a reference to the current blueprint, if any."""
+        menu_items = defaultdict(list)
+        for blueprint in app.submodules:
+            menu_items.update(getattr(blueprint, "menu_items", {}))
+        return {
+            'current_app': current_app,
+            'current_blueprint': current_blueprint,
+            'menu_items': menu_items }
+
     ##########################################################################
     # All done!
     ##########################################################################
 
     app.logger.debug('URL map: %s' % app.url_map)
     return app
-
diff --git a/web/pgadmin/about/__init__.py b/web/pgadmin/about/__init__.py
index e69de29..5830c7c 100644
--- a/web/pgadmin/about/__init__.py
+++ b/web/pgadmin/about/__init__.py
@@ -0,0 +1,67 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2015, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the about box."""
+MODULE_NAME = 'about'
+
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.menu import MenuItem
+from flask import Response, current_app, render_template, __version__, url_for
+from flask.ext.babel import gettext
+from flask.ext.security import current_user, login_required
+
+import sys
+
+import config
+
+class AboutModule(PgAdminModule):
+
+    def get_own_menuitems(self):
+        return {
+            'help_items': [
+                MenuItem(name='mnu_about',
+                         priority=999,
+                         url='#',
+                         onclick='about_show()',
+                         label=gettext('About %(appname)s', appname=config.APP_NAME))
+            ]
+        }
+
+    def get_own_javascripts(self):
+        return [url_for('about.script')]
+
+
+blueprint = AboutModule(MODULE_NAME, __name__,
+                        static_url_path='')
+
+##########################################################################
+# A test page
+##########################################################################
+@blueprint.route("/")
+@login_required
+def index():
+    """Render the about box."""
+    info = { }
+    info['python_version'] = sys.version
+    info['flask_version'] = __version__
+    if config.SERVER_MODE == True:
+        info['app_mode'] = gettext('Server')
+    else:
+        info['app_mode'] = gettext('Desktop')
+    info['current_user'] = current_user.email
+
+    return render_template(MODULE_NAME + '/index.html', info=info)
+
+@blueprint.route("/about.js")
+@login_required
+def script():
+    """Render the required Javascript"""
+    return Response(response=render_template("about/about.js"),
+                    status=200,
+                    mimetype="application/javascript")
diff --git a/web/pgadmin/about/hooks.py b/web/pgadmin/about/hooks.py
deleted file mode 100644
index f0c0ac8..0000000
--- a/web/pgadmin/about/hooks.py
+++ /dev/null
@@ -1,28 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Browser integration functions for the About module."""
-
-from flask import render_template, url_for
-from flask.ext.babel import gettext
-
-import config
-
-def get_help_menu_items():
-    """Return a (set) of dicts of help menu items, with name, priority, URL, 
-    target and onclick code."""
-    return [{'name': 'mnu_about',
-             'label': gettext('About %(appname)s', appname=config.APP_NAME), 
-             'priority': 999, 
-             'url': "#", 
-             'onclick': "about_show()"}]
-
-def get_scripts():
-    """Return a list of script URLs to include in the rendered page header"""
-    return [ url_for('about.script') ]
\ No newline at end of file
diff --git a/web/pgadmin/about/views.py b/web/pgadmin/about/views.py
deleted file mode 100644
index 0966a16..0000000
--- a/web/pgadmin/about/views.py
+++ /dev/null
@@ -1,48 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module implementing the about box."""
-MODULE_NAME = 'about'
-
-from flask import Blueprint, Response, current_app, render_template, __version__
-from flask.ext.babel import gettext
-from flask.ext.security import current_user, login_required
-
-import sys
-
-import config
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static',  static_url_path='', template_folder='templates', url_prefix='/' + MODULE_NAME)
-
-##########################################################################
-# A test page
-##########################################################################
-@blueprint.route("/")
-@login_required
-def index():
-    """Render the about box."""
-    info = { }
-    info['python_version'] = sys.version
-    info['flask_version'] = __version__
-    if config.SERVER_MODE == True:
-        info['app_mode'] = gettext('Server')
-    else:
-        info['app_mode'] = gettext('Desktop')
-    info['current_user'] = current_user.email
-    
-    return render_template(MODULE_NAME + '/index.html', info=info)
-    
-@blueprint.route("/about.js")
-@login_required
-def script():
-    """Render the required Javascript"""
-    return Response(response=render_template("about/about.js"),
-                    status=200,
-                    mimetype="application/javascript")
\ No newline at end of file
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 5442b7d..ae42104 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -6,7 +6,159 @@
 # This software is released under the PostgreSQL Licence
 #
 ##########################################################################
+from abc import ABCMeta, abstractmethod, abstractproperty
+from pgadmin import current_blueprint
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.ajax import make_json_response
+from pgadmin.settings import get_setting
+from flask import current_app, render_template, url_for, make_response
+from flask.ext.security import login_required
+from flask.ext.login import current_user
+from flaskext.gravatar import Gravatar
 
-# Define the node lists
-all_nodes = [ ]
-sub_nodes = [ ]
\ No newline at end of file
+MODULE_NAME = 'browser'
+
+class BrowserModule(PgAdminModule):
+
+
+    def get_own_stylesheets(self):
+        stylesheets = []
+        # Add browser stylesheets
+        for (endpoint, filename) in [
+            ('static', 'css/codemirror/codemirror.css'),
+            ('static', 'css/jQuery-contextMenu/jquery.contextMenu.css'),
+            ('static', 'css/wcDocker/wcDockerSkeleton.css' if \
+                    current_app.debug else \
+                       'css/wcDocker/wcDockerSkeleton.min.css'),
+            ('static', 'css/wcDocker/theme.css'),
+            ('browser.static', 'css/aciTree/css/aciTree.css'),
+            ]:
+            stylesheets.append(url_for(endpoint, filename=filename))
+        stylesheets.append(url_for('browser.browser_css'))
+        return stylesheets
+
+
+    def get_own_javascripts(self):
+        scripts = []
+        for (endpoint, filename) in [
+            ('static', 'js/codemirror/codemirror.js'),
+            ('static', 'js/codemirror/mode/sql.js'),
+            ('static', 'js/jQuery-contextMenu/jquery.ui.position.js'),
+            ('static', 'js/jQuery-contextMenu/jquery.contextMenu.js'),
+            ('browser.static', 'js/aciTree/jquery.aciPlugin.min.js'),
+            ('browser.static', 'js/aciTree/jquery.aciTree.dom.js'),
+            ('browser.static', 'js/aciTree/jquery.aciTree.min.js')]:
+            scripts.append(url_for(endpoint, filename=filename))
+        scripts.append(url_for('browser.browser_js'))
+        if current_app.debug:
+            scripts.append(url_for(
+                'static',
+                filename='js/wcDocker/wcDocker.js'))
+        else:
+            scripts.append(url_for(
+                'static',
+                filename='js/wcDocker/wcDocker.min.js'))
+        return scripts
+
+
+blueprint = BrowserModule(MODULE_NAME, __name__)
+
+class BrowserPluginModule(PgAdminModule):
+    """
+    Base class for browser submodules.
+    """
+
+    __metaclass__ = ABCMeta
+
+    def __init__(self, import_name, **kwargs):
+        kwargs.setdefault("url_prefix", self.node_path)
+        kwargs.setdefault("static_url_path", 'static')
+        super(BrowserPluginModule, self).__init__("NODE-%s" % self.node_type,
+                                            import_name,
+                                            **kwargs)
+
+
+    @property
+    @abstractmethod
+    def jssnippets(self):
+        """
+        Returns a snippet of javascript to include in the page
+        """
+        # TODO: move those methods to BrowserModule subclass ?
+        return []
+
+    @property
+    def csssnippets(self):
+        """
+        Returns a snippet of css to include in the page
+        """
+        # TODO: move those methods to BrowserModule subclass ?
+        return [render_template("browser/css/node.css",
+                               node_type=self.node_type)]
+
+    @abstractmethod
+    def get_nodes(self):
+        """
+        Each browser module is responsible for fetching
+        its own tree subnodes.
+        """
+        return []
+
+    @abstractproperty
+    def node_type(self):
+        pass
+
+    @property
+    def node_path(self):
+        return '/browser/nodes/' + self.node_type
+
+
+@blueprint.route("/")
+@login_required
+def index():
+    """Render and process the main browser window."""
+    # Get the Gravatar
+    gravatar = Gravatar(current_app,
+                        size=100,
+                        rating='g',
+                        default='retro',
+                        force_default=False,
+                        use_ssl=False,
+                        base_url=None)
+    return render_template(MODULE_NAME + "/index.html",
+                           username=current_user.email)
+
+@blueprint.route("/browser.js")
+@login_required
+def browser_js():
+    layout = get_setting('Browser/Layout', default='')
+    snippets = []
+    for submodule in current_blueprint.submodules:
+        snippets.extend(submodule.jssnippets)
+    return make_response(
+            render_template(
+                'browser/js/browser.js',
+                layout=layout,
+                jssnippets=snippets),
+            200, {'Content-Type': 'application/x-javascript'})
+
+@blueprint.route("/browser.css")
+@login_required
+def browser_css():
+    """Render and return CSS snippets from the nodes and modules."""
+    snippets = []
+    for submodule in current_blueprint.submodules:
+        snippets.extend(submodule.csssnippets)
+    return make_response(
+            render_template('browser/css/browser.css', snippets=snippets),
+            200, {'Content-Type': 'text/css'})
+
+
+@blueprint.route("/nodes/")
+@login_required
+def get_nodes():
+    """Build a list of treeview nodes from the child nodes."""
+    nodes = []
+    for submodule in current_blueprint.submodules:
+        nodes.extend(submodule.get_nodes())
+    return make_json_response(data=nodes)
diff --git a/web/pgadmin/browser/hooks.py b/web/pgadmin/browser/hooks.py
deleted file mode 100644
index c382795..0000000
--- a/web/pgadmin/browser/hooks.py
+++ /dev/null
@@ -1,21 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Browser application hooks"""
-
-import os, sys
-import config
-
-from pgadmin.browser.utils import register_modules
-from pgadmin.browser import all_nodes
-from . import sub_nodes
-
-def register_submodules(app):
-    """Register any child node blueprints"""
-    register_modules(app, __file__, all_nodes, sub_nodes, 'pgadmin.browser')
diff --git a/web/pgadmin/browser/server_groups/__init__.py b/web/pgadmin/browser/server_groups/__init__.py
index 95535f7..b5a4167 100644
--- a/web/pgadmin/browser/server_groups/__init__.py
+++ b/web/pgadmin/browser/server_groups/__init__.py
@@ -6,10 +6,237 @@
 # This software is released under the PostgreSQL Licence
 #
 ##########################################################################
+"""Defines views for management of server groups"""
 
-# Node meta data
-NODE_TYPE = 'server-group'
-NODE_PATH = '/browser/nodes/' + NODE_TYPE
+from abc import ABCMeta, abstractmethod
+import traceback
+from flask import Blueprint, Response, current_app, request, render_template
+from flask.ext.babel import gettext
+from flask.ext.security import current_user, login_required
+from pgadmin import current_blueprint
+from pgadmin.utils.ajax import make_json_response
+from pgadmin.browser import BrowserPluginModule
+from pgadmin.utils.menu import MenuItem
+from pgadmin.settings.settings_model import db, ServerGroup
+from pgadmin.browser.utils import generate_browser_node
+import config
 
-# Define the child node list
-sub_nodes = [ ]
\ No newline at end of file
+
+class ServerGroupModule(BrowserPluginModule):
+
+    NODE_TYPE = "server-group"
+
+    def get_own_menuitems(self):
+        return {
+            'standard_items': [
+                ServerGroupMenuItem(action="drop", priority=10, function="drop_server_group"),
+                ServerGroupMenuItem(action="rename", priority=10, function="rename_server_group")
+            ],
+            'create_items': [
+                ServerGroupMenuItem(name="create_server_group",
+                                    label=gettext('Server Group...'),
+                                    priority=10,
+                                    function="create_server_group",
+                                    types=[self.node_type])
+            ],
+            'context_items': [
+                ServerGroupMenuItem(name="delete_server_group",
+                                    label=gettext('Delete server group'),
+                                    priority=10,
+                                    onclick='drop_server_group(item);'),
+                ServerGroupMenuItem(name="rename_server_group",
+                                    label=gettext('Rename server group...'),
+                                    priority=10,
+                                    onclick='rename_server_group(item);')
+            ]
+        }
+
+
+    @property
+    def jssnippets(self):
+        snippets = [render_template("server_groups/server_groups.js")]
+        for module in self.submodules:
+            snippets.extend(module.jssnippets)
+        return snippets
+
+    def get_nodes(self, **kwargs):
+        """Return a JSON document listing the server groups for the user"""
+        groups = ServerGroup.query.filter_by(user_id=current_user.id)
+        # TODO: Move this JSON generation to a Server method
+        # this code is duplicated somewhere else
+        for group in groups:
+            yield generate_browser_node(
+                    "%d" % (group.id),
+                    group.name,
+                    "icon-%s" % self.node_type,
+                    True,
+                    self.node_type)
+
+    @property
+    def node_type(self):
+        return self.NODE_TYPE
+
+    @property
+    def node_path(self):
+        return '/browser/' + self.node_type
+
+
+class ServerGroupMenuItem(MenuItem):
+
+    def __init__(self, **kwargs):
+        kwargs.setdefault("type", ServerGroupModule.NODE_TYPE)
+        super(ServerGroupMenuItem, self).__init__(**kwargs)
+
+
+class ServerGroupPluginModule(BrowserPluginModule):
+    """
+    Base class for server group plugins.
+    """
+
+    __metaclass__ = ABCMeta
+
+
+    @abstractmethod
+    def get_nodes(self, servergroup):
+        pass
+
+
+    @property
+    def node_path(self):
+        return '/browser/' + self.node_type
+
+
+blueprint = ServerGroupModule( __name__, static_url_path='')
+
+# Initialise the module
+from pgadmin.browser.utils import NodeView
+
+
+class ServerGroupView(NodeView):
+
+    node_type = ServerGroupModule.NODE_TYPE
+    parent_ids = []
+    ids = [{'type':'int', 'id':'gid'}]
+
+
+    def list(self):
+        res = []
+        for g in blueprint.get_nodes():
+            res.append(g)
+        return make_json_response(result=res)
+
+
+    def delete(self, gid):
+        """Delete a server group node in the settings database"""
+
+        # There can be only one record at most
+        servergroup = ServerGroup.query.filter_by(
+                user_id=current_user.id,
+                id=gid)
+
+        if servergroup is None:
+            return make_json_response(
+                    success=0,
+                    errormsg=gettext('The specified server group could not be found.'))
+        else:
+            try:
+                db.session.delete(servergroup)
+                db.session.commit()
+            except Exception as e:
+                return make_json_response(success=0, errormsg=e.message)
+
+        return make_json_response(result=request.form)
+
+
+    def update(self, gid):
+        """Update the server-group properties"""
+
+        # There can be only one record at most
+        servergroup = ServerGroup.query.filter_by(
+                user_id=current_user.id,
+                id=gid).first()
+
+        if servergroup is None:
+            return make_json_response(
+                    success=0,
+                    errormsg=gettext('The specified server group could not be found.'))
+        else:
+            try:
+                if 'name' in request.form:
+                    servergroup.name = request.form['name']
+                db.session.commit()
+            except Exception as e:
+                return make_json_response(success=0, errormsg=e.message)
+
+        return make_json_response(result=request.form)
+
+
+    def properties(self, gid):
+        """Update the server-group properties"""
+
+        # There can be only one record at most
+        sg = ServerGroup.query.filter_by(
+                user_id=current_user.id,
+                id=gid).first()
+        data = {}
+
+        if sg is None:
+            return make_json_response(
+                    success=0,
+                    errormsg=gettext('The specified server group could not be found.'))
+        else:
+            return make_json_response(data={'id': sg.id, 'name': sg.name})
+
+
+    def create(self):
+        data = []
+        if request.form['name'] != '':
+            servergroup = ServerGroup(
+                    user_id=current_user.id,
+                    name=request.form['name'])
+            try:
+                db.session.add(servergroup)
+                db.session.commit()
+
+                data['id'] = servergroup.id
+                data['name'] = servergroup.name
+            except Exception as e:
+                return make_json_response(success=0, errormsg=e.message)
+
+        else:
+            return make_json_response(
+                    success=0,
+                    errormsg=gettext('No server group name was specified'))
+
+        return make_json_response(data=data)
+
+
+    def nodes(self, gid):
+        """Build a list of treeview nodes from the child nodes."""
+        nodes = []
+        for module in blueprint.submodules:
+            nodes.extend(module.get_nodes(server_group=gid))
+        return make_json_response(data=nodes)
+
+
+    def sql(self, gid):
+        return make_json_response(data='')
+
+
+    def modified_sql(self, gid):
+        return make_json_response(data='')
+
+
+    def statistics(self, gid):
+        return make_json_response(data='')
+
+
+    def dependencies(self, gid):
+        return make_json_response(data='')
+
+
+    def dependents(self, gid):
+        return make_json_response(data='')
+
+
+ServerGroupView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/hooks.py b/web/pgadmin/browser/server_groups/hooks.py
deleted file mode 100644
index 248b733..0000000
--- a/web/pgadmin/browser/server_groups/hooks.py
+++ /dev/null
@@ -1,76 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Integration hooks for server groups."""
-
-from flask import render_template, url_for
-from flask.ext.babel import gettext
-from flask.ext.security import current_user
-
-from pgadmin.browser.utils import register_modules
-from pgadmin.settings.settings_model import db, ServerGroup
-
-from pgadmin.browser import all_nodes
-from . import NODE_TYPE, sub_nodes
-
-def register_submodules(app):
-    """Register any child node blueprints"""
-    register_modules(app, __file__, all_nodes, sub_nodes, 'pgadmin.browser.server_groups')
-    
-def get_nodes():
-    """Return a JSON document listing the server groups for the user"""
-    groups = ServerGroup.query.filter_by(user_id=current_user.id)
-    
-    value = ''
-    for group in groups:
-        value += '{"id":"%s/%d","label":"%s","icon":"icon-%s","inode":true,"_type":"%s"},' % (NODE_TYPE, group.id, group.name, NODE_TYPE, NODE_TYPE)
-    value = value[:-1]
-    
-    return value
-
-    
-def get_standard_menu_items():
-    """Return a (set) of dicts of standard menu items (create/drop/rename), with 
-    object type, action and the function name (no parens) to call on click."""
-    return [
-            {'type': 'server-group', 'action': 'drop', 'priority': 10, 'function': 'drop_server_group'},
-            {'type': 'server-group', 'action': 'rename', 'priority': 20, 'function': 'rename_server_group'}
-           ]
-
-
-def get_create_menu_items():
-    """Return a (set) of dicts of create menu items, with a Javascript array of 
-    object types on which the option should appear, name, label and the function 
-    name (no parens) to call on click."""
-    return [
-            {'type': "['server-group']", 'name': 'create_server_group', 'label': gettext('Server Group...'), 'priority': 10, 'function': 'create_server_group'}
-           ]
-    
-    
-def get_context_menu_items():
-    """Return a (set) of dicts of content menu items with name, node type, label, priority and JS"""
-    return [
-            {'name': 'delete_server_group', 'type': NODE_TYPE, 'label': gettext('Delete server group'), 'priority': 10, 'onclick': 'drop_server_group(item);'},
-            {'name': 'rename_server_group', 'type': NODE_TYPE, 'label': gettext('Rename server group...'), 'priority': 20, 'onclick': 'rename_server_group(item);'}
-           ]
-    
-    
-def get_script_snippets():
-    """Return the script snippets needed to handle treeview node operations."""
-    return render_template('server_groups/server_groups.js')
-
-
-def get_css_snippets():
-    """Return the CSS needed to display the treeview node image."""
-    css = ".icon-server-group {\n"
-    css += " background: url('%s') 0 0 no-repeat !important;\n" % \
-            url_for('NODE-%s.static' % NODE_TYPE, filename='img/server-group.png')
-    css += "}\n"
-    
-    return css
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index a9e5e3c..68e501c 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -6,11 +6,294 @@
 # This software is released under the PostgreSQL Licence
 #
 ##########################################################################
+from flask import render_template, request
+from pgadmin.browser.server_groups import ServerGroupPluginModule
+from flask.ext.security import login_required, current_user
+from pgadmin.settings.settings_model import db, Server, ServerGroup
+from pgadmin.utils.menu import MenuItem
+from pgadmin.utils.ajax import make_json_response
+from pgadmin.browser.utils import generate_browser_node, NodeView
+import traceback
+from flask.ext.babel import gettext
 
-# Node meta data
-NODE_TYPE = 'server'
-NODE_PATH = '/browser/nodes/' + NODE_TYPE
 
-# Define the child node list
-sub_nodes = [ ]
+class ServerModule(ServerGroupPluginModule):
 
+    NODE_TYPE = "server"
+
+    @property
+    def node_type(self):
+        return self.NODE_TYPE
+
+    def get_nodes(self, server_group):
+        """Return a JSON document listing the server groups for the user"""
+        servers = Server.query.filter_by(user_id=current_user.id, servergroup_id=server_group)
+
+        # TODO: Move this JSON generation to a Server method
+        for server in servers:
+            yield generate_browser_node(
+                    "%d" % server.id,
+                    server.name,
+                    "icon-%s" % self.NODE_TYPE,
+                    True,
+                    self.NODE_TYPE
+                    )
+
+    def get_own_menuitems(self):
+        return {
+            'standard_items': [
+                ServerMenuItem(action="drop", priority=50, function='drop_server'),
+                ServerMenuItem(action="rename", priority=50, function='rename_server')
+            ],
+            'create_items': [
+                ServerMenuItem(types=["server-group", "server"],
+                               name="create_server",
+                               label=gettext('Server...'),
+                               priority=50,
+                               function='create_server(item)')
+            ],
+            'context_items': [
+                ServerMenuItem(name='delete_server',
+                               label=gettext('Delete server'),
+                               priority=50,
+                               onclick='drop_server(item)'),
+                ServerMenuItem(name='rename_server',
+                               label=gettext('Rename server...'),
+                               priority=60,
+                               onclick='rename_server(item);')
+            ]
+        }
+
+
+    @property
+    def jssnippets(self):
+        return [render_template("servers/servers.js")]
+
+
+class ServerMenuItem(MenuItem):
+
+    def __init__(self, **kwargs):
+        kwargs.setdefault("type", ServerModule.NODE_TYPE)
+        super(ServerMenuItem, self).__init__(**kwargs)
+
+
+blueprint = ServerModule(__name__)
+
+
+class ServerNode(NodeView):
+
+    node_type = ServerModule.NODE_TYPE
+    parent_ids = [{'type':'int', 'id':'gid'}]
+    ids = [{'type':'int', 'id':'sid'}]
+
+
+    def list(self, gid):
+        res = []
+        """Return a JSON document listing the server groups for the user"""
+        servers = Server.query.filter_by(user_id=current_user.id,
+                servergroup_id=gid)
+
+        for server in servers:
+            res.append(
+                    generate_browser_node(
+                        "%d/%d" % (gid, server.id),
+                        server.name,
+                        "icon-%s" % NODE_TYPE,
+                        True,
+                        NODE_TYPE
+                        )
+                    )
+        return make_json_response(result=res)
+
+
+    def delete(self, gid, sid):
+        """Delete a server node in the settings database"""
+        server = Server.query.filter_by(user_id=current_user.id, id=sid)
+
+        # TODO:: A server, which is connected, can not be deleted
+        if server is None:
+            return make_json_response(
+                    success=0,
+                    errormsg=gettext(
+                        'The specified server could not be found.\n'
+                        'Does the user have permission to access the '
+                        'server?'
+                        )
+                    )
+        else:
+            try:
+                db.session.delete(server)
+                db.session.commit()
+            except Exception as e:
+                return make_json_response(
+                        success=0,
+                        errormsg=e.message)
+
+        return make_json_response(success=success,
+                errormsg=errormsg,
+                info=traceback.format_exc())
+
+
+    def update(self, gid, sid):
+        """Update the server settings"""
+        server = Server.query.filter_by(user_id=current_user.id, id=sid).first()
+
+        if server is None:
+            return make_json_response(
+                    success=0,
+                    errormsg=gettext("Couldn't find the given server.")
+                    )
+
+        # TODO::
+        #   Not all parameters can be modified, while the server is connected
+        possible_args = {
+                'name': 'name',
+                'host': 'host',
+                'port': 'port',
+                'db': 'maintenance_db',
+                'username': 'username',
+                'sslmode': 'sslmode',
+                'gid': 'servergroup_id'
+                }
+
+        idx = 0
+        for arg in possible_args:
+            if arg in request.form:
+                server[possible_args[arg]] = request.form[arg]
+                idx += 1
+
+        if idx == 0:
+            return make_json_response(
+                    success=0,
+                    errormsg=gettext('No parameters were chagned!')
+                    )
+
+        try:
+            db.session.commit()
+        except Exception as e:
+            return make_json_response(
+                    success=0,
+                    errormsg=e.message
+                    )
+
+        return make_json_response(
+                success=1,
+                data={
+                    'id': server.id,
+                    'gid': server.servergroup_id
+                    }
+                )
+
+
+    def properties(self, gid, sid):
+        """Return list of attributes of a server"""
+        server = Server.query.filter_by(
+                user_id=current_user.id,
+                id=sid).first()
+
+        if server is None:
+            return make_json_response(
+                    success=0,
+                    errormsg=gettext("Couldn't find the given server")
+                    )
+
+        sg = ServerGroup.query.filter_by(
+                user_id=current_user.id,
+                id=server.servergroup_id
+                ).first()
+
+        return make_json_response(
+                success=1,
+                data={
+                    'id':server.id,
+                    'name':server.name,
+                    'host':server.host,
+                    'port':server.port,
+                    'db':server.maintenance_db,
+                    'username':server.username,
+                    'gid':server.servergroup_id,
+                    'group-name':sg.name
+                    }
+                )
+
+
+    def create(self, gid):
+        """Add a server node to the settings database"""
+        required_args = [
+                'name',
+                'host',
+                'port',
+                'db',
+                'username',
+                'sslmode'
+                ]
+
+        for arg in required_args:
+            if arg not in request.form:
+                return make_json_response(
+                        success=0,
+                        errormsg=gettext(
+                            "Couldn't find the required parameter (%s)." % arg
+                            )
+                        )
+
+        server = Server(
+                user_id=current_user.id,
+                servergroup_id=gid,
+                name=request.form['name'],
+                host=request.form['host'],
+                port=request.form['port'],
+                maintenance_db=request.form['db'],
+                username=request.form['username'],
+                sslmode=request.form['username']
+                )
+
+        try:
+            db.session.add(server)
+            db.session.commit()
+        except Exception as e:
+            return make_json_response(
+                    success=0,
+                    errormsg=e.message
+                    )
+
+        return make_json_response(success=1,
+                data={
+                    'id': server.id,
+                    'name': server.name,
+                    'gid': gid
+                    })
+
+
+    def nodes(self, gid, sid):
+        """Build a list of treeview nodes from the child nodes."""
+        nodes = []
+        # TODO::
+        # We can have nodes for the server object, only when
+        # the server is connected at the moment.
+        for module in blueprint.submodules:
+            nodes.extend(module.get_nodes(server=sid))
+        return make_json_response(data=nodes)
+
+
+    def sql(self, gid, sid):
+        return make_json_response(data='')
+
+
+    def modified_sql(self, gid, sid):
+        return make_json_response(data='')
+
+
+    def statistics(self, gid, sid):
+        return make_json_response(data='')
+
+
+    def dependencies(self, gid, sid):
+        return make_json_response(data='')
+
+
+    def dependents(self, gid, sid):
+        return make_json_response(data='')
+
+
+ServerNode.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/hooks.py b/web/pgadmin/browser/server_groups/servers/hooks.py
deleted file mode 100644
index 6178b9b..0000000
--- a/web/pgadmin/browser/server_groups/servers/hooks.py
+++ /dev/null
@@ -1,69 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Integration hooks for servers."""
-
-from flask import render_template, url_for
-from flask.ext.babel import gettext
-from flask.ext.security import current_user
-
-from pgadmin.settings.settings_model import db, Server
-from . import NODE_TYPE
-
-def get_nodes(server_group):
-    """Return a JSON document listing the server groups for the user"""
-    servers = Server.query.filter_by(user_id=current_user.id, servergroup_id=server_group)
-    
-    value = ''
-    for server in servers:
-        value += '{"id":"%s/%d","label":"%s","icon":"icon-%s","inode":true,"_type":"%s"},' % (NODE_TYPE, server.id, server.name, NODE_TYPE, NODE_TYPE)
-    value = value[:-1]
-    
-    return value
-
-    
-def get_standard_menu_items():
-    """Return a (set) of dicts of standard menu items (create/drop/rename), with 
-    object type, action, priority and the function to call on click."""
-    return [
-            {'type': 'server', 'action': 'drop', 'priority': 50, 'function': 'drop_server'},
-            {'type': 'server', 'action': 'rename', 'priority': 60, 'function': 'rename_server'}
-           ]
-    
-
-def get_create_menu_items():
-    """Return a (set) of dicts of create menu items, with a Javascript array of 
-    object types on which the option should appear, name, label, priority and 
-    the function name (no parens) to call on click."""
-    return [
-            {'type': "['server-group', 'server']", 'name': 'create_server', 'label': gettext('Server...'), 'priority': 50, 'function': 'create_server'}
-           ]
-
-
-def get_context_menu_items():
-    """Return a (set) of dicts of content menu items with name, node type, label, priority and JS"""
-    return [
-            {'name': 'delete_server', 'type': NODE_TYPE, 'label': gettext('Delete server'), 'priority': 50, 'onclick': 'drop_server(item);'},
-            {'name': 'rename_server', 'type': NODE_TYPE, 'label': gettext('Rename server...'), 'priority': 60, 'onclick': 'rename_server(item);'}
-           ]
-    
-    
-def get_script_snippets():
-    """Return the script snippets needed to handle treeview node operations."""
-    return render_template('servers/servers.js')
-
-
-def get_css_snippets():
-    """Return the CSS needed to display the treeview node image."""
-    css = ".icon-server {\n"
-    css += " background: url('%s') 0 0 no-repeat !important;\n" % \
-            url_for('NODE-%s.static' % NODE_TYPE, filename='img/server.png')
-    css += "}\n"
-    
-    return css
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js
index 822441d..5361229 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js
@@ -1,11 +1,18 @@
 // Add a server
-function create_server() {
+function create_server(item) {
     var alert = alertify.prompt(
         '{{ _('Create a server') }}',
         '{{ _('Enter a name for the new server') }}', 
         '', 
         function(evt, value) { 
-            $.post("{{ url_for('NODE-server.add') }}", { name: value })
+            var d = tree.itemData(item);
+            if (d._type != 'server-group') {
+                d = tree.itemData(tree.parent(item));
+            }
+            $.post(
+                "{{ url_for('browser.index') }}server/obj/" + d.refid + '/',
+                { name: value }
+                )
                 .done(function(data) {
                     if (data.success == 0) {
                         report_error(data.errormsg, data.info);
@@ -38,8 +45,10 @@ function drop_server(item) {
         '{{ _('Are you sure you wish to drop the server "{0}"?') }}'.replace('{0}', tree.getLabel(item)),
         function() {
             var id = tree.getId(item).split('/').pop()
-            $.post("{{ url_for('NODE-server.delete') }}", { id: id })
-                .done(function(data) {
+            $.ajax({
+                url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid,
+                type:'DELETE',
+                success: function(data) {
                     if (data.success == 0) {
                         report_error(data.errormsg, data.info);
                     } else {
@@ -53,7 +62,7 @@ function drop_server(item) {
                         }
                     }
                 }
-            )
+            })
         },
         null
     )
@@ -66,17 +75,20 @@ function rename_server(item) {
         '{{ _('Enter a new name for the server') }}', 
         tree.getLabel(item), 
         function(evt, value) {
-            var id = tree.getId(item).split('/').pop()
-            $.post("{{ url_for('NODE-server.rename') }}", { id: id, name: value })
-                .done(function(data) {
+            var d = tree.itemData(item);
+            $.ajax({
+                url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid,
+                type:'PUT',
+                params: {name: value},
+                success: function(data) {
                     if (data.success == 0) {
                         report_error(data.errormsg, data.info);
                     } else {
                         tree.setLabel(item, { label: value });
                     }
                 }
-            )
+            })
         },
         null
     )
-}
\ No newline at end of file
+}
diff --git a/web/pgadmin/browser/server_groups/servers/views.py b/web/pgadmin/browser/server_groups/servers/views.py
deleted file mode 100644
index 318b365..0000000
--- a/web/pgadmin/browser/server_groups/servers/views.py
+++ /dev/null
@@ -1,117 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Defines views for management of servers"""
-
-from flask import Blueprint, Response, current_app, request
-from flask.ext.babel import gettext
-from flask.ext.security import current_user, login_required
-
-from . import NODE_TYPE, NODE_PATH
-from pgadmin.utils.ajax import make_json_response
-from pgadmin.settings.settings_model import db, ServerGroup
-import config
-
-# Initialise the module
-blueprint = Blueprint("NODE-" + NODE_TYPE, __name__, static_folder='static',  static_url_path='', template_folder='templates', url_prefix=NODE_PATH)
-
-@blueprint.route('/add/', methods=['POST'])
-@login_required
-def add():
-    """Add a server node to the settings database"""
-    success = 1
-    errormsg = ''
-    data = { }
-    
-    if request.form['name'] != '':
-        server = Server(user_id=current_user.id, name=request.form['name'])
-
-        try:
-            db.session.add(server)
-            db.session.commit()
-        except Exception as e:
-            success = 0
-            errormsg = e.message
-
-    else:
-        success = 0
-        errormsg = gettext('No server name was specified')
-            
-    if success == 1:
-        data['id'] = server.id
-        data['name'] = server.name
-        
-    return make_json_response(success=success, 
-                              errormsg=errormsg, 
-                              info=traceback.format_exc(), 
-                              result=request.form, 
-                              data=data)
-
-@blueprint.route('/delete/', methods=['POST'])
-@login_required
-def delete():
-    """Delete a server node in the settings database"""
-    success = 1
-    errormsg = ''
-
-    if request.form['id'] != '':
-        # There can be only one record at most
-        servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
-        
-        if server is None:
-            success = 0
-            errormsg = gettext('The specified server could not be found.')
-        else:
-            try:
-                db.session.delete(server)
-                db.session.commit()
-            except Exception as e:
-                success = 0
-                errormsg = e.message
-
-    else:
-        success = 0
-        errormsg = gettext('No server was specified.')
-            
-    return make_json_response(success=success, 
-                              errormsg=errormsg, 
-                              info=traceback.format_exc(), 
-                              result=request.form)
-
-@blueprint.route('/rename/', methods=['POST'])
-@login_required
-def rename():
-    """Rename a server node in the settings database"""
-    success = 1
-    errormsg = ''
-
-    if request.form['id'] != '':
-        # There can be only one record at most
-        servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
-        
-        if server is None:
-            success = 0
-            errormsg = gettext('The specified server could not be found.')
-        else:
-            try:
-                server.name = request.form['name']
-                db.session.commit()
-            except Exception as e:
-                success = 0
-                errormsg = e.message
-
-    else:
-        success = 0
-        errormsg = gettext('No server was specified.')
-            
-    return make_json_response(success=success, 
-                              errormsg=errormsg, 
-                              info=traceback.format_exc(), 
-                              result=request.form)
-    
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js b/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js
index 29b5449..a154012 100644
--- a/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js
+++ b/web/pgadmin/browser/server_groups/templates/server_groups/server_groups.js
@@ -5,7 +5,7 @@ function create_server_group() {
         '{{ _('Enter a name for the new server group') }}', 
         '', 
         function(evt, value) { 
-            $.post("{{ url_for('NODE-server-group.add') }}", { name: value })
+            $.post("{{ url_for('browser.index') }}server-group/obj/", { name: value })
                 .done(function(data) {
                     if (data.success == 0) {
                         report_error(data.errormsg, data.info);
@@ -37,9 +37,11 @@ function drop_server_group(item) {
         '{{ _('Delete server group?') }}',
         '{{ _('Are you sure you wish to delete the server group "{0}"?') }}'.replace('{0}', tree.getLabel(item)),
         function() {
-            var id = tree.getId(item).split('/').pop()
-            $.post("{{ url_for('NODE-server-group.delete') }}", { id: id })
-                .done(function(data) {
+            var d = tree.itemData(item);
+            $.ajax({
+                url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid,
+                type:'DELETE',
+                success: function(data) {
                     if (data.success == 0) {
                         report_error(data.errormsg, data.info);
                     } else {
@@ -53,7 +55,7 @@ function drop_server_group(item) {
                         }
                     }
                 }
-            )
+            })
         },
         null
     )
@@ -66,17 +68,20 @@ function rename_server_group(item) {
         '{{ _('Enter a new name for the server group') }}', 
         tree.getLabel(item), 
         function(evt, value) {
-            var id = tree.getId(item).split('/').pop()
-            $.post("{{ url_for('NODE-server-group.rename') }}", { id: id, name: value })
-                .done(function(data) {
+            var d = tree.itemData(item);
+            $.ajax({
+                url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid,
+                type:'PUT',
+                params: { name: value },
+                success: function(data) {
                     if (data.success == 0) {
                         report_error(data.errormsg, data.info);
                     } else {
                         tree.setLabel(item, { label: value });
                     }
                 }
-            )
+            })
         },
         null
     )
-}
\ No newline at end of file
+}
diff --git a/web/pgadmin/browser/server_groups/views.py b/web/pgadmin/browser/server_groups/views.py
deleted file mode 100644
index b0f5551..0000000
--- a/web/pgadmin/browser/server_groups/views.py
+++ /dev/null
@@ -1,140 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Defines views for management of server groups"""
-
-import traceback
-from flask import Blueprint, Response, current_app, request
-from flask.ext.babel import gettext
-from flask.ext.security import current_user, login_required
-
-from . import NODE_TYPE, NODE_PATH, sub_nodes
-from pgadmin.utils.ajax import make_json_response
-from pgadmin.settings.settings_model import db, ServerGroup
-import config
-
-# Initialise the module
-blueprint = Blueprint("NODE-" + NODE_TYPE, __name__, static_folder='static',  static_url_path='', template_folder='templates', url_prefix=NODE_PATH)
-
-@blueprint.route("/<server_group>")
-@login_required
-def get_nodes(server_group):
-    """Build a list of treeview nodes from the child nodes."""
-    value = '['
-    
-    for node in sub_nodes:
-        if 'hooks' in dir(node) and 'get_nodes' in dir(node.hooks):
-            value += node.hooks.get_nodes(server_group) + ','
-        
-    if value[-1:] == ',':
-        value = value[:-1]
-        
-    value += ']'
-    
-    resp = Response(response=value,
-                status=200,
-                mimetype="text/json")
-    
-    return resp
-    
-    
-@blueprint.route('/add/', methods=['POST'])
-@login_required
-def add():
-    """Add a server group node to the settings database"""
-    success = 1
-    errormsg = ''
-    data = { }
-    
-    if request.form['name'] != '':
-        servergroup = ServerGroup(user_id=current_user.id, name=request.form['name'])
-
-        try:
-            db.session.add(servergroup)
-            db.session.commit()
-        except Exception as e:
-            success = 0
-            errormsg = e.message
-
-    else:
-        success = 0
-        errormsg = gettext('No server group name was specified')
-            
-    if success == 1:
-        data['id'] = servergroup.id
-        data['name'] = servergroup.name
-        
-    return make_json_response(success=success, 
-                              errormsg=errormsg, 
-                              info=traceback.format_exc(), 
-                              result=request.form, 
-                              data=data)
-
-@blueprint.route('/delete/', methods=['POST'])
-@login_required
-def delete():
-    """Delete a server group node in the settings database"""
-    success = 1
-    errormsg = ''
-
-    if request.form['id'] != '':
-        # There can be only one record at most
-        servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
-        
-        if servergroup is None:
-            success = 0
-            errormsg = gettext('The specified server group could not be found.')
-        else:
-            try:
-                db.session.delete(servergroup)
-                db.session.commit()
-            except Exception as e:
-                success = 0
-                errormsg = e.message
-
-    else:
-        success = 0
-        errormsg = gettext('No server group  was specified.')
-            
-    return make_json_response(success=success, 
-                              errormsg=errormsg, 
-                              info=traceback.format_exc(), 
-                              result=request.form)
-
-@blueprint.route('/rename/', methods=['POST'])
-@login_required
-def rename():
-    """Rename a server group node in the settings database"""
-    success = 1
-    errormsg = ''
-
-    if request.form['id'] != '':
-        # There can be only one record at most
-        servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
-        
-        if servergroup is None:
-            success = 0
-            errormsg = gettext('The specified server group could not be found.')
-        else:
-            try:
-                servergroup.name = request.form['name']
-                db.session.commit()
-            except Exception as e:
-                success = 0
-                errormsg = e.message
-
-    else:
-        success = 0
-        errormsg = gettext('No server group was specified.')
-            
-    return make_json_response(success=success, 
-                              errormsg=errormsg, 
-                              info=traceback.format_exc(), 
-                              result=request.form)
-    
\ No newline at end of file
diff --git a/web/pgadmin/browser/templates/browser/css/browser.css b/web/pgadmin/browser/templates/browser/css/browser.css
new file mode 100644
index 0000000..9fb9ed4
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/css/browser.css
@@ -0,0 +1,3 @@
+{% for snip in snippets %}
+{{ snip }}
+{% endfor %}
diff --git a/web/pgadmin/browser/templates/browser/css/node.css b/web/pgadmin/browser/templates/browser/css/node.css
new file mode 100644
index 0000000..da56d69
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/css/node.css
@@ -0,0 +1,3 @@
+.icon-{{node_type}} {
+  background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.png' % node_type )}}') !important;
+}
diff --git a/web/pgadmin/browser/templates/browser/index.html b/web/pgadmin/browser/templates/browser/index.html
index 481d268..dd3a4b2 100644
--- a/web/pgadmin/browser/templates/browser/index.html
+++ b/web/pgadmin/browser/templates/browser/index.html
@@ -31,39 +31,22 @@
             <li><a id="mnu_drop_object" href="#" onclick="drop_object()">{{ _('Drop object') }}</a></li>
             <li><a id="mnu_rename_object" href="#" onclick="rename_object()">{{ _('Rename object') }}</a></li>
             <li class="divider"></li>
-            {% if file_items is defined and file_items|count > 0 %}{% for file_item in file_items %}
-            <li><a id="{{ file_item.name }}" href="{{ file_item.url }}"{% if file_item.target %} target="{{ file_item.target }}"{% endif %}{% if file_item.onclick %} onclick="{{ file_item.onclick|safe }}"{% endif %}>{{ file_item.label }}</a></li>{% endfor %}{% endif %}
+            {% for file_item in menu_items.file_items %}
+            <li><a id="{{ file_item.name }}" href="{{ file_item.url }}"{% if file_item.target %} target="{{ file_item.target }}"{% endif %}{% if file_item.onclick %} onclick="{{ file_item.onclick|safe }}"{% endif %}>{{ file_item.label }}</a></li>{% endfor %}
           </ul>
         </li>
-
-        {% if edit_items is defined and edit_items|count > 0 %}<li class="dropdown">
-          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ _('Edit') }} <span class="caret"></span></a>
-          <ul class="dropdown-menu" role="menu">{% for edit_item in edit_items %}
-            <li><a id="{{ edit_item.name }}" href="{{ edit_item.url }}"{% if edit_item.target %} target="{{ edit_item.target }}"{% endif %}{% if edit_item.onclick %} onclick="{{ edit_item.onclick|safe }}"{% endif %}>{{ edit_item.label }}</a></li>{% endfor %}
-          </ul>
-        </li>{% endif %}
-        
-        {% if tools_items is defined and tools_items|count > 0 %}<li class="dropdown">
-          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ _('Tools') }} <span class="caret"></span></a>
-          <ul class="dropdown-menu" role="menu">{% for tools_item in tools_items %}
-            <li><a id="{{ tools_item.name }}" href="{{ tools_item.url }}"{% if tools_item.target %} target="{{ tools_item.target }}"{% endif %}{% if tools_item.onclick %} onclick="{{ tools_item.onclick|safe }}"{% endif %}>{{ tools_item.label }}</a></li>{% endfor %}
-          </ul>
-        </li>{% endif %}
-        
-        {% if management_items is defined and management_items|count > 0 %}<li class="dropdown">
-          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ _('Management') }} <span class="caret"></span></a>
-          <ul class="dropdown-menu" role="menu">{% for management_item in management_items %}
-            <li><a id="{{ management_item.name }}" href="{{ management_item.url }}"{% if management_item.target %} target="{{ management_item.target }}"{% endif %}{% if management_item.onclick %} onclick="{{ management_item.onclick|safe }}"{% endif %}>{{ management_item.label }}</a></li>{% endfor %}
-          </ul>
-        </li>{% endif %}
-        
-        {% if help_items is defined and help_items|count > 0 %}<li class="dropdown">
-          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ _('Help') }} <span class="caret"></span></a>
-          <ul class="dropdown-menu" role="menu">{% for help_item in help_items %}
-            <li><a id="{{ help_item.name }}" href="{{ help_item.url }}"{% if help_item.target %} target="{{ help_item.target }}"{% endif %}{% if help_item.onclick %} onclick="{{ help_item.onclick|safe }}"{% endif %}>{{ help_item.label }}</a></li>{% endfor %}
-          </ul>
-        </li>{% endif %}
-
+        {% for key in ('Edit', 'Tools', 'Management', 'Help') %}
+          {% if menu_items['%s_items' % key.lower()] %}
+        <li class="dropdown">
+          <a href="#" class="dropdown-toggle" data-toggle="dropdown"
+            role="button" aria-expanded="false">{{ _(key) }} <span class="caret"></span></a>
+            <ul class="dropdown-menu" role="menu">
+              {% for item in menu_items['%s_items' % key.lower()] %}
+              <li><a id="{{ item.name }}" href="{{ item.url }}"{% if item.target %} target="{{ item.target }}"{% endif %}{% if item.onclick %} onclick="{{ item.onclick|safe }}"{% endif %}>{{ item.label }}</a></li>
+              {% endfor %}
+            </ul>
+        </li>{%endif%}
+        {% endfor %}
       </ul>
       {% if config.SERVER_MODE %}
       <ul class="nav navbar-nav navbar-right">
diff --git a/web/pgadmin/browser/templates/browser/js/browser.js b/web/pgadmin/browser/templates/browser/js/browser.js
index 16025f1..dbdf034 100644
--- a/web/pgadmin/browser/templates/browser/js/browser.js
+++ b/web/pgadmin/browser/templates/browser/js/browser.js
@@ -1,21 +1,21 @@
 // Page globals
-var docker
-var editor
-var tree
-var dashboardPanel
-var propertiesPanel
-var statisticsPanel
-var dependenciesPanel
-var dependentsPanel
-var sqlPanel
-var browserPanel
+var docker;
+var editor;
+var tree;
+var dashboardPanel;
+var propertiesPanel;
+var statisticsPanel;
+var dependenciesPanel;
+var dependentsPanel;
+var sqlPanel;
+var browserPanel;
 
 // Store the main browser layout
-$(window).bind('unload', function() { 
+$(window).bind('unload', function() {
     state = docker.save();
-    settings = { setting: "Browser/Layout", 
+    settings = { setting: "Browser/Layout",
                  value: state }
-    
+
     $.post("{{ url_for('settings.store') }}", settings);
 
     return true
@@ -28,8 +28,8 @@ function buildPanel(docker, name, title, width, height, showTitle, isCloseable,
         isPrivate: isPrivate,
         onCreate: function(myPanel) {
             myPanel.initSize(width, height);
-            
-            if (showTitle == false) 
+
+            if (showTitle == false)
                 myPanel.title(false);
 
             myPanel.closeable(isCloseable);
@@ -46,8 +46,8 @@ function buildIFramePanel(docker, name, title, width, height, showTitle, isClose
         isPrivate: isPrivate,
         onCreate: function(myPanel) {
             myPanel.initSize(width, height);
-            
-            if (showTitle == false) 
+
+            if (showTitle == false)
                 myPanel.title(false);
 
             myPanel.closeable(isCloseable);
@@ -87,7 +87,7 @@ function report_error(message, info) {
       <div class="panel-body" style="overflow: scroll;">' + message + '</div>\
     </div>\
   </div>'
-  
+
     if (info != null && info != '') {
         text += '<div class="panel panel-default">\
     <div class="panel-heading" role="tab" id="headingTwo">\
@@ -103,9 +103,9 @@ function report_error(message, info) {
   </div>\
 </div>'
     }
-    
+
     text += '</div>'
-    
+
     alertify.alert(
         '{{ _('An error has occurred') }}',
         text
@@ -115,35 +115,35 @@ function report_error(message, info) {
 
 // Enable/disable menu options
 function enable_disable_menus() {
-    
+
     // Disable everything first
     $("#mnu_create").html('<li class="menu-item disabled"><a href="#">{{ _('No object selected') }}</a></li>\n');
-    $("#mnu_drop_object").addClass("mnu-disabled"); 
-    $("#mnu_rename_object").addClass("mnu-disabled"); 
+    $("#mnu_drop_object").addClass("mnu-disabled");
+    $("#mnu_rename_object").addClass("mnu-disabled");
     node_type = get_selected_node_type()
-    
+
     // List the possible standard items, their types and actions
-    var handlers = [{% if standard_items is defined %}{% for standard_item in standard_items %}
-        "{{ standard_item.type }}:{{ standard_item.action }}",{% endfor %}{% endif %} 
+    var handlers = [{% for standard_item in menu_items.standard_items %}
+        "{{ standard_item.type }}:{{ standard_item.action }}",{% endfor %}
     ]
-    
+
     // Check if we have a matching action for the object type in the list, and
     // if so, enable the menu item
     if ($.inArray(node_type + ":drop", handlers) >= 0)
-        $("#mnu_drop_object").removeClass("mnu-disabled"); 
-        
+        $("#mnu_drop_object").removeClass("mnu-disabled");
+
     if ($.inArray(node_type + ":rename", handlers) >= 0)
         $("#mnu_rename_object").removeClass("mnu-disabled");
-        
+
     // List the possibe create items
-    var creators = [{% if create_items is defined %}{% for create_item in create_items %}
-        [{{ create_item.type }}, "{{ create_item.name }}", "{{ create_item.label }}", "{{ create_item.function }}"],{% endfor %}{% endif %} 
+    var creators = [{% for create_item in menu_items.create_items %}
+        [{{ create_item.types | tojson }}, "{{ create_item.name }}", "{{ create_item.label }}", "{{ create_item.function }}"],{% endfor %}
     ]
-    
+
     // Loop through the list of creators and add links for any that apply to this
     // node type to the Create menu's UL element
     items = ''
-    
+
     for (i = 0; i < creators.length; ++i) {
         if ($.inArray(node_type, creators[i][0]) >= 0) {
             items = items + '<li class="menu-item"><a href="#" onclick="' + creators[i][3] + '()">' + creators[i][2] + '</a></li>\n'
@@ -158,22 +158,22 @@ function get_selected_node_type() {
     item = tree.selected()
     if (!item || item.length != 1)
         return "";
-        
+
     return tree.itemData(tree.selected())._type;
 }
-    
+
 // Create a new object of the type currently selected
 function create_object() {
     node_type = get_selected_node_type()
     if (node_type == "")
         return;
-    
+
     switch(node_type) {
-    {% if standard_items is defined %}{% for standard_item in standard_items %}{% if standard_item.action == 'create' %}
+    {% for standard_item in menu_items.standard_items %}{% if standard_item.action == 'create' %}
         case '{{ standard_item.type }}':
              {{ standard_item.function }}()
              break;
-    {% endif %}{% endfor %}{% endif %} 
+    {% endif %}{% endfor %}
     }
 }
 
@@ -182,13 +182,13 @@ function drop_object() {
     node_type = get_selected_node_type()
     if (node_type == "")
         return;
-    
+
     switch(node_type) {
-    {% if standard_items is defined %}{% for standard_item in standard_items %}{% if standard_item.action == 'drop' %}
+    {% for standard_item in menu_items.standard_items %}{% if standard_item.action == 'drop' %}
         case '{{ standard_item.type }}':
              {{ standard_item.function }}(tree.selected())
              break;
-    {% endif %}{% endfor %}{% endif %} 
+    {% endif %}{% endfor %}
     }
 }
 
@@ -197,13 +197,13 @@ function rename_object() {
     node_type = get_selected_node_type()
     if (node_type == "")
         return;
-    
+
     switch(node_type) {
-    {% if standard_items is defined %}{% for standard_item in standard_items %}{% if standard_item.action == 'rename' %}
+    {% for standard_item in menu_items.standard_items %}{% if standard_item.action == 'rename' %}
         case '{{ standard_item.type }}':
              {{ standard_item.function }}(tree.selected())
              break;
-    {% endif %}{% endfor %}{% endif %} 
+    {% endif %}{% endfor %}
     }
 }
 
@@ -237,37 +237,37 @@ WITH ( \n\
 ); \n\
 ALTER TABLE tickets_detail \n\
   OWNER TO helpdesk;\n';
-  
-        buildPanel(docker, 'pnl_browser', '{{ _('Browser') }}', 300, 600, false, false, true, 
+
+        buildPanel(docker, 'pnl_browser', '{{ _('Browser') }}', 300, 600, false, false, true,
                   '<div id="tree" class="aciTree">')
-        buildIFramePanel(docker, 'pnl_dashboard', '{{ _('Dashboard') }}', 500, 600, true, false, true, 
+        buildIFramePanel(docker, 'pnl_dashboard', '{{ _('Dashboard') }}', 500, 600, true, false, true,
                   'http://www.pgadmin.org/')
-        buildPanel(docker, 'pnl_properties', '{{ _('Properties') }}', 500, 600, true, false, true, 
+        buildPanel(docker, 'pnl_properties', '{{ _('Properties') }}', 500, 600, true, false, true,
                   '<p>Properties pane</p>')
-        buildPanel(docker, 'pnl_sql', '{{ _('SQL') }}', 500, 600, true, false, true, 
+        buildPanel(docker, 'pnl_sql', '{{ _('SQL') }}', 500, 600, true, false, true,
                   '<textarea id="sql-textarea" name="sql-textarea">' + demoSql + '</textarea>')
-        buildPanel(docker, 'pnl_statistics', '{{ _('Statistics') }}', 500, 600, true, false, true, 
+        buildPanel(docker, 'pnl_statistics', '{{ _('Statistics') }}', 500, 600, true, false, true,
                   '<p>Statistics pane</p>')
-        buildPanel(docker, 'pnl_dependencies', '{{ _('Dependencies') }}', 500, 600, true, false, true, 
+        buildPanel(docker, 'pnl_dependencies', '{{ _('Dependencies') }}', 500, 600, true, false, true,
                   '<p>Depedencies pane</p>')
-        buildPanel(docker, 'pnl_dependents', '{{ _('Dependents') }}', 500, 600, true, false, true, 
+        buildPanel(docker, 'pnl_dependents', '{{ _('Dependents') }}', 500, 600, true, false, true,
                   '<p>Dependents pane</p>')
-        
+
         // Add hooked-in panels
-        {% if panel_items is defined and panel_items|count > 0 %}{% for panel_item in panel_items %}{% if panel_item.isIframe %}
-        buildIFramePanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}', 
-                                  {{ panel_item.width }}, {{ panel_item.height }}, 
-                                  {{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }}, 
+        {% for panel_item in current_app.panels %}{% if panel_item.isIframe %}
+        buildIFramePanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}',
+                                  {{ panel_item.width }}, {{ panel_item.height }},
+                                  {{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }},
                                   {{ panel_item.isPrivate|lower }}, '{{ panel_item.content }}')
         {% else %}
-        buildPanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}', 
-                            {{ panel_item.width }}, {{ panel_item.height }}, 
-                            {{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }}, 
-                            {{ panel_item.isPrivate|lower }}, '{{ panel_item.content }}')                         
-        {% endif %}{% endfor %}{% endif %}
-        
+        buildPanel(docker, '{{ panel_item.name }}', '{{ panel_item.title }}',
+                            {{ panel_item.width }}, {{ panel_item.height }},
+                            {{ panel_item.showTitle|lower }}, {{ panel_item.isCloseable|lower }},
+                            {{ panel_item.isPrivate|lower }}, '{{ panel_item.content }}')
+        {% endif %}{% endfor %}
+
         var layout = '{{ layout }}';
-        
+
         // Try to restore the layout if there is one
         if (layout != '') {
             try {
@@ -281,7 +281,7 @@ ALTER TABLE tickets_detail \n\
             buildDefaultLayout()
         }
     }
-    
+
     // Syntax highlight the SQL Pane
     editor = CodeMirror.fromTextArea(document.getElementById("sql-textarea"), {
         lineNumbers: true,
@@ -292,8 +292,19 @@ ALTER TABLE tickets_detail \n\
     // Initialise the treeview
     $('#tree').aciTree({
         ajax: {
-            url: '{{ url_for('browser.get_nodes') }}'
+            url: '{{ url_for('browser.get_nodes') }}',
+            converters: {
+                'text json': function(payload) {
+                    return $.parseJSON(payload).data;
+                }
+            }
         },
+        ajaxHook: function(item, settings) {
+            if (item != null) {
+                var d = this.itemData(item);
+                settings.url = '{{ url_for('browser.index') }}' + d._type + '/nodes/' + d.refid
+            }
+        }
     });
     tree = $('#tree').aciTree('api');
 
@@ -305,22 +316,20 @@ ALTER TABLE tickets_detail \n\
             var menu = { };
             var createMenu = { };
 
-            {% if create_items is defined %}
-            {% for create_item in create_items %}
-            if ($.inArray(tree.itemData(item)._type, {{ create_item.type }}) >= 0) {
+            {% for create_item in menu_items.create_items %}
+            if ($.inArray(tree.itemData(item)._type, {{ create_item.types | tojson }}) >= 0) {
                 createMenu['{{ create_item.name }}'] = { name: '{{ create_item.label }}', callback: function() { {{ create_item.function }}() }};
             }
-            {% endfor %}{% endif %}
-            
-            menu["create"] = { "name": "Create" }            
+            {% endfor %}
+
+            menu["create"] = { "name": "Create" }
             menu["create"]["items"] = createMenu
-            
-            {% if context_items is defined %}
-            {% for context_item in context_items %}
+
+            {% for context_item in menu_items.context_items %}
             if (tree.itemData(item)._type == '{{ context_item.type }}') {
                 menu['{{ context_item.name }}'] = { name: '{{ context_item.label }}', callback: function() { {{ context_item.onclick }} }};
             }
-            {% endfor %}{% endif %}
+            {% endfor %}
             return {
                 autoHide: true,
                 items: menu,
@@ -328,7 +337,7 @@ ALTER TABLE tickets_detail \n\
             };
         }
     });
-    
+
     // Treeview event handler
     $('#tree').on('acitree', function(event, api, item, eventName, options){
         switch (eventName){
@@ -338,9 +347,11 @@ ALTER TABLE tickets_detail \n\
         }
     });
 
-    
+
     // Setup the menus
     enable_disable_menus()
 });
 
-
+{% for snippet in jssnippets %}
+    {{ snippet }}
+{% endfor %}
diff --git a/web/pgadmin/browser/utils.py b/web/pgadmin/browser/utils.py
index 4cf955f..ec9858a 100644
--- a/web/pgadmin/browser/utils.py
+++ b/web/pgadmin/browser/utils.py
@@ -9,45 +9,173 @@
 
 """Browser helper utilities"""
 
-import os, sys
-import config
-
-def register_modules(app, file, all_nodes, sub_nodes, prefix):
-    """Register any child node blueprints for the specified file"""
-    path = os.path.dirname(os.path.realpath(file))
-    files = os.listdir(path)
-
-    for f in files:
-        d = os.path.join(path, f)
-        if os.path.isdir(d) and os.path.isfile(os.path.join(d, '__init__.py')):
-
-            if f in config.NODE_BLACKLIST:
-                app.logger.info('Skipping blacklisted node: %s' % f)
-                continue
-
-            # Construct the 'real' module name
-            if prefix != '':
-                f = prefix + '.' + f
-                
-            # Looks like a node, so import it, and register the blueprint if present
-            # We rely on the ordering of syspath to ensure we actually get the right
-            # module here. 
-            app.logger.info('Examining potential node: %s' % d)
-            node = __import__(f, globals(), locals(), ['hooks', 'views'], -1)
-
-            # Add the node to the node lists
-            all_nodes.append(node)
-            sub_nodes.append(node)
-            
-            # Register the blueprint if present
-            if 'views' in dir(node) and 'blueprint' in dir(node.views):
-                app.logger.info('Registering blueprint node: %s' % f)
-                app.register_blueprint(node.views.blueprint)
-                app.logger.debug('   - root_path:       %s' % node.views.blueprint.root_path)
-                app.logger.debug('   - static_folder:   %s' % node.views.blueprint.static_folder)
-                app.logger.debug('   - template_folder: %s' % node.views.blueprint.template_folder)
-                
-            # Register any sub-modules
-            if 'hooks' in dir(node) and 'register_submodules' in dir(node.hooks):
-                app.logger.info('Registering sub-modules in %s' % f)
-                node.hooks.register_submodules(app)
\ No newline at end of file
+from flask import request
+from flask.views import View, MethodViewType, with_metaclass
+
+
+def generate_browser_node(node_id, label, icon, inode, node_type):
+    return {
+            "id": "%s/%s" % (node_type, node_id),
+            "label": label,
+            "icon": icon,
+            "inode": inode,
+            "_type": node_type,
+            "refid": node_id 
+    }
+
+
+class NodeView(with_metaclass(MethodViewType, View)):
+    """
+    A PostgreSQL Object has so many operaions/functions apart from CRUD
+    (Create, Read, Update, Delete):
+    i.e.
+    - Reversed Engineered SQL
+    - Modified Query for parameter while editing object attributes
+      i.e. ALTER TABLE ...
+    - Statistics of the objects
+    - List of dependents
+    - List of dependencies
+    - Listing of the children object types for the certain node
+      It will used by the browser tree to get the children nodes
+
+    This class can be inherited to achieve the diffrent routes for each of the
+    object types/collections.
+
+    OPERATION      |              URL       | Method
+    ---------------+------------------------+--------
+    List           | /obj/[Parent URL]/     | GET
+    Properties     | /obj/[Parent URL]/id   | GET
+    Create         | /obj/[Parent URL]/     | POST
+    Delete         | /obj/[Parent URL]/id   | DELETE
+    Update         | /obj/[Parent URL]/id   | PUT
+
+    SQL (Reversed  | /sql/[Parent URL]/id   | GET
+    Engineering)   |
+    SQL (Modified  | /sql/[Parent URL]/id   | POST
+    Properties)    |
+
+    Statistics     | /stats/[Parent URL]/id | GET
+    Dependencies   | /deps/[Parent URL]/id  | GET
+    Dependents     | /deps/[Parent URL]/id  | POST
+
+    Children Nodes | /nodes/[Parent URL]/id | GET
+
+    NOTE:
+    Parent URL can be seen as the path to identify the particular node.
+
+    i.e.
+    In order to identify the TABLE object, we need server -> database -> schema
+    information.
+    """
+    operations = {
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'nodes': [{'get': 'nodes'}, {}],
+        'sql': [{'get': 'sql', 'post': 'modified_sql'}, {}],
+        'stats': [{'get': 'statistics'}, {}],
+        'deps': [{'get': 'dependencies', 'post': 'dependents'}, {}]
+    }
+
+
+    @classmethod
+    def generate_ops(cls):
+        cmds = []
+        for op in cls.operations:
+            idx=0
+            for ops in cls.operations[op]:
+                meths = []
+                for meth in ops:
+                    meths.append(meth.upper())
+                if len(meths) > 0:
+                    cmds.append({'cmd': op, 'req':idx==0, 'methods': meths})
+                idx+=1
+
+        return cmds
+
+
+    # Inherited class needs to modify these parameters
+    node_type = None
+    # This must be an array object with attributes (type and id)
+    parent_ids = []
+    # This must be an array object with attributes (type and id)
+    ids = []
+
+
+    @classmethod
+    def get_node_urls(cls):
+        assert cls.node_type is not None, "Please set the node_type for this class (%r)" % cls
+        common_url = '/'
+        for p in cls.parent_ids:
+            common_url += '<' + p['type'] + ":" + p['id'] + '>/'
+
+        id_url = common_url
+        idx = 0
+        for p in cls.ids:
+            id_url += '/<' if idx == 1 else '<' + p['type'] + ":" + p['id'] + '>'
+            idx += 1
+
+        return id_url, common_url
+
+
+    def __init__(self, cmd):
+        self.cmd = cmd;
+
+
+    # Check the existance of all the required arguments from parent_ids
+    # and return combination of has parent arguments, and has id arguments
+    def check_args(self, *args, **kwargs):
+        has_id = has_args = True
+        for p in self.parent_ids:
+            if p['id'] not in kwargs:
+                has_args = False
+                break
+
+        for p in self.ids:
+            if p['id'] not in kwargs:
+                has_id = False
+                break
+
+        return has_args, has_id and has_args
+
+
+    def dispatch_request(self, *args, **kwargs):
+        meth = request.method.lower()
+        if meth == 'head':
+            meth = 'get'
+
+        assert self.cmd in NodeView.operations, \
+                "Unimplemented Command (%s) for Node View" % self.cmd
+        has_args, has_id = self.check_args(*args, **kwargs)
+
+        assert (has_id and meth in NodeView.operations[self.cmd][0]) \
+                or (not has_id and meth in NodeView.operations[self.cmd][1]), \
+                "Unimplemented method (%s) for command (%s), which %s an id" \
+                % (meth, self.cmd, 'requires' if has_id else 'does not require')
+
+        meth = NodeView.operations[self.cmd][0][meth] if has_id else \
+                NodeView.operations[self.cmd][1][meth]
+
+        method = getattr(self, meth, None)
+
+        assert method is not None, \
+                "Unimplemented method (%s) for this url (%u)" % \
+                (meth, request.path)
+
+        return method(*args, **kwargs)
+
+
+    @classmethod
+    def register_node_view(cls, blueprint):
+        id_url, url = cls.get_node_urls()
+
+        commands = cls.generate_ops()
+
+        for c in commands:
+            blueprint.add_url_rule(
+                    '/%s%s' % (c['cmd'], id_url if c['req'] else url),
+                    view_func=cls.as_view(
+                        '%s%s' % (c['cmd'], '_id' if c['req'] else ''),
+                        cmd=c['cmd']),
+                    methods=c['methods'])
diff --git a/web/pgadmin/browser/views.py b/web/pgadmin/browser/views.py
deleted file mode 100644
index 07637be..0000000
--- a/web/pgadmin/browser/views.py
+++ /dev/null
@@ -1,226 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module implementing the core pgAdmin browser."""
-MODULE_NAME = 'browser'
-
-from flask import Blueprint, Response, current_app, render_template, url_for
-from flaskext.gravatar import Gravatar
-from flask.ext.security import login_required
-from flask.ext.login import current_user
-from inspect import getmoduleinfo, getmembers
-
-from . import sub_nodes
-from pgadmin.browser import all_nodes
-from pgadmin import modules
-from pgadmin.settings import get_setting
-
-
-import config
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='/' + MODULE_NAME)
-
-@blueprint.route("/")
-@login_required
-def index():
-    """Render and process the main browser window."""
-    # Get the Gravatar
-    gravatar = Gravatar(current_app,
-                        size=100,
-                        rating='g',
-                        default='retro',
-                        force_default=False,
-                        use_ssl=False,
-                        base_url=None)
-
-    # Get the plugin elements from the module
-    file_items = [ ]
-    edit_items = [ ]
-    tools_items = [ ]
-    management_items = [ ]
-    help_items = [ ]
-    stylesheets = [ ]
-    scripts = [ ]
-
-    modules_and_nodes = modules + all_nodes
-        
-    # Add browser stylesheets
-    stylesheets.append(url_for('static', filename='css/codemirror/codemirror.css'))
-
-    if config.DEBUG:
-        stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.css'))
-    else:
-        stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.min.css'))
-
-    stylesheets.append(url_for('static', filename='css/wcDocker/theme.css'))
-    stylesheets.append(url_for('static', filename='css/jQuery-contextMenu/jQuery.contextMenu.css'))
-    stylesheets.append(url_for('browser.static', filename='css/browser.css'))
-    stylesheets.append(url_for('browser.static', filename='css/aciTree/css/aciTree.css'))
-    stylesheets.append(url_for('browser.browser_css'))
-    
-    # Add browser scripts
-    scripts.append(url_for('static', filename='js/codemirror/codemirror.js'))
-    scripts.append(url_for('static', filename='js/codemirror/mode/sql.js'))
-    
-    if config.DEBUG:
-        scripts.append(url_for('static', filename='js/wcDocker/wcDocker.js'))
-    else:
-        scripts.append(url_for('static', filename='js/wcDocker/wcDocker.min.js'))
-
-    scripts.append(url_for('static', filename='js/jQuery-contextMenu/jquery.ui.position.js'))
-    scripts.append(url_for('static', filename='js/jQuery-contextMenu/jQuery.contextMenu.js'))
-    scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciPlugin.min.js'))
-    scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.dom.js'))
-    scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.min.js'))
-    scripts.append(url_for('browser.browser_js'))
-    
-    for module in modules_and_nodes:
-        # Get the edit menu items
-        if 'hooks' in dir(module) and 'get_file_menu_items' in dir(module.hooks):
-            file_items.extend(module.hooks.get_file_menu_items())
-    
-        # Get the edit menu items
-        if 'hooks' in dir(module) and 'get_edit_menu_items' in dir(module.hooks):
-            edit_items.extend(module.hooks.get_edit_menu_items())
-
-        # Get the tools menu items
-        if 'hooks' in dir(module) and 'get_tools_menu_items' in dir(module.hooks):
-            tools_items.extend(module.hooks.get_tools_menu_items())
-
-        # Get the management menu items
-        if 'hooks' in dir(module) and 'get_management_menu_items' in dir(module.hooks):
-            management_items.extend(module.hooks.get_management_menu_items())
-                
-        # Get the help menu items
-        if 'hooks' in dir(module) and 'get_help_menu_items' in dir(module.hooks):
-            help_items.extend(module.hooks.get_help_menu_items())
-                    
-        # Get any stylesheets
-        if 'hooks' in dir(module) and 'get_stylesheets' in dir(module.hooks):
-            stylesheets += module.hooks.get_stylesheets()
-                    
-        # Get any scripts
-        if 'hooks' in dir(module) and 'get_scripts' in dir(module.hooks):
-            scripts += module.hooks.get_scripts()
-            
-    file_items = sorted(file_items, key=lambda k: k['priority'])
-    edit_items = sorted(edit_items, key=lambda k: k['priority'])
-    tools_items = sorted(tools_items, key=lambda k: k['priority'])
-    management_items = sorted(management_items, key=lambda k: k['priority'])
-    help_items = sorted(help_items, key=lambda k: k['priority'])
-
-    return render_template(MODULE_NAME + '/index.html', 
-                           username=current_user.email, 
-                           file_items=file_items, 
-                           edit_items=edit_items, 
-                           tools_items=tools_items, 
-                           management_items=management_items,
-                           help_items=help_items,
-                           stylesheets = stylesheets,
-                           scripts = scripts)
-
-@blueprint.route("/browser.js")
-@login_required
-def browser_js():
-    """Render and return JS snippets from the nodes and modules."""
-    snippets = ''
-    modules_and_nodes = modules + all_nodes
-    
-    # Load the core browser code first
-    
-    # Get the context menu items
-    standard_items = [ ]
-    create_items = [ ]
-    context_items = [ ]
-    panel_items = [ ]
-    
-    for module in modules_and_nodes:
-        # Get any standard menu items
-        if 'hooks' in dir(module) and 'get_standard_menu_items' in dir(module.hooks):
-            standard_items.extend(module.hooks.get_standard_menu_items())
-
-        # Get any create menu items
-        if 'hooks' in dir(module) and 'get_create_menu_items' in dir(module.hooks):
-            create_items.extend(module.hooks.get_create_menu_items())
-            
-        # Get any context menu items
-        if 'hooks' in dir(module) and 'get_context_menu_items' in dir(module.hooks):
-            context_items.extend(module.hooks.get_context_menu_items())
-            
-        # Get any panels
-        if 'hooks' in dir(module) and 'get_panels' in dir(module.hooks):
-            panel_items += module.hooks.get_panels()
-
-    standard_items = sorted(standard_items, key=lambda k: k['priority'])
-    create_items = sorted(create_items, key=lambda k: k['priority'])
-    context_items = sorted(context_items, key=lambda k: k['priority'])
-    panel_items = sorted(panel_items, key=lambda k: k['priority'])
-    
-    layout = get_setting('Browser/Layout', default='')
-    
-    snippets += render_template('browser/js/browser.js', 
-                                layout = layout,
-                                standard_items = standard_items,
-                                create_items = create_items,
-                                context_items = context_items,
-                                panel_items = panel_items)
-    
-    # Add module and node specific code
-    for module in modules_and_nodes:
-        if 'hooks' in dir(module) and 'get_script_snippets' in dir(module.hooks):
-            snippets += module.hooks.get_script_snippets()
-    
-    resp = Response(response=snippets,
-                status=200,
-                mimetype="application/javascript")
-    
-    return resp
-
-@blueprint.route("/browser.css")
-@login_required
-def browser_css():
-    """Render and return CSS snippets from the nodes and modules."""
-    snippets = ''
-    modules_and_nodes = modules + all_nodes
-    
-    for module in modules_and_nodes:
-        if 'hooks' in dir(module) and 'get_css_snippets' in dir(module.hooks):
-            snippets += module.hooks.get_css_snippets()
-            
-    resp = Response(response=snippets,
-                status=200,
-                mimetype="text/css")
-    
-    return resp
-
-
-@blueprint.route("/nodes/")
-@login_required
-def get_nodes():
-    """Build a list of treeview nodes from the child nodes."""
-    value = '['
-    
-    for node in sub_nodes:
-        if 'hooks' in dir(node) and 'get_nodes' in dir(node.hooks):
-            value += node.hooks.get_nodes() + ','
-        
-    if value[-1:] == ',':
-        value = value[:-1]
-        
-    value += ']'
-    
-    resp = Response(response=value,
-                status=200,
-                mimetype="text/json")
-    
-    return resp
-    
-        
-        
\ No newline at end of file
diff --git a/web/pgadmin/help/__init__.py b/web/pgadmin/help/__init__.py
index e69de29..6d753f8 100644
--- a/web/pgadmin/help/__init__.py
+++ b/web/pgadmin/help/__init__.py
@@ -0,0 +1,66 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2015, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the pgAdmin help system."""
+MODULE_NAME = 'help'
+
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.menu import MenuItem, Panel
+from flask.ext.babel import gettext
+from flask import url_for
+import config
+
+
+class HelpModule(PgAdminModule):
+
+    def get_own_menuitems(self):
+        """Return a (set) of dicts of help menu items, with name, priority, URL,
+        target and onclick code."""
+        return { 'help_items': [
+            MenuItem(name='mnu_online_help',
+                     label=gettext('Online Help'),
+                     priority=100,
+                     target='_new',
+                     url=url_for('help.static', filename='index.html')),
+
+            MenuItem(name='mnu_pgadmin_website',
+                     label= gettext('pgAdmin Website'),
+                     priority= 200,
+                     target= '_new',
+                     url= 'http://www.pgadmin.org/' ),
+
+            MenuItem(name= 'mnu_postgresql_website',
+                     label= gettext('PostgreSQL Website'),
+                     priority= 300,
+                     target= '_new',
+                     url= 'http://www.postgresql.org/' )]}
+
+    def get_panels(self):
+        return [
+            Panel(
+                name='pnl_online_help',
+                priority=100,
+                title=gettext('Online Help'),
+                content=url_for('help.static', filename='index.html')),
+
+            Panel(name='pnl_pgadmin_website',
+                  priority=200,
+                  title=gettext('pgAdmin Website'),
+                  content='http://www.pgadmin.org/'),
+
+            Panel(name='pnl_postgresql_website',
+                  priority=300,
+                  title=gettext('PostgreSQL Website'),
+                  content='http://www.postgresql.org/')]
+
+
+
+# Initialise the module
+blueprint = HelpModule(MODULE_NAME, __name__, static_url_path='/help',
+                       static_folder=config.HELP_PATH)
diff --git a/web/pgadmin/help/hooks.py b/web/pgadmin/help/hooks.py
deleted file mode 100644
index 9fb5bc6..0000000
--- a/web/pgadmin/help/hooks.py
+++ /dev/null
@@ -1,73 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Browser integration functions for the Help module."""
-
-from flask import url_for
-from flask.ext.babel import gettext
-
-import config
-
-def get_help_menu_items():
-    """Return a (set) of dicts of help menu items, with name, priority, URL, 
-    target and onclick code."""
-    return [{'name': 'mnu_online_help',
-             'label': gettext('Online Help'), 
-             'priority': 100, 
-             'target': '_new',
-             'url': url_for('help.static', filename='index.html') },
-             
-            {'name': 'mnu_pgadmin_website',
-             'label': gettext('pgAdmin Website'), 
-             'priority': 200, 
-             'target': '_new',
-             'url': 'http://www.pgadmin.org/' },
-             
-             {'name': 'mnu_postgresql_website',
-             'label': gettext('PostgreSQL Website'), 
-             'priority': 300, 
-             'target': '_new',
-             'url': 'http://www.postgresql.org/' }]
-    
-def get_panels():
-    """Return a (set) of dicts describing panels to create in the browser. Fields
-    are name, priority, title, width, height, isIframe, showTitle, isCloseable, 
-    isPrivate and content"""
-    return [{'name': 'pnl_online_help',
-             'priority': 100,
-             'title': gettext('Online Help'),
-             'width': 500,
-             'height': 600,
-             'isIframe': True,
-             'showTitle': True,
-             'isCloseable': True,
-             'isPrivate': False,
-             'content': url_for('help.static', filename='index.html') },
-             
-            {'name': 'pnl_pgadmin_website',
-             'priority': 200,
-             'title': gettext('pgAdmin Website'),
-             'width': 500,
-             'height': 600,
-             'isIframe': True,
-             'showTitle': True,
-             'isCloseable': True,
-             'isPrivate': False,
-             'content': 'http://www.pgadmin.org/' },
-             
-            {'name': 'pnl_postgresql_website',
-             'priority': 300,
-             'title': gettext('PostgreSQL Website'),
-             'width': 500,
-             'height': 600,
-             'isIframe': True,
-             'showTitle': True,
-             'isCloseable': True,
-             'isPrivate': False,
-             'content': 'http://www.postgresql.org/' }]
\ No newline at end of file
diff --git a/web/pgadmin/help/views.py b/web/pgadmin/help/views.py
deleted file mode 100644
index 10ad910..0000000
--- a/web/pgadmin/help/views.py
+++ /dev/null
@@ -1,18 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module implementing the pgAdmin help system."""
-MODULE_NAME = 'help'
-
-from flask import Blueprint
-
-import config
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, static_url_path='/help', static_folder=config.HELP_PATH)
diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py
index e69de29..1f6973c 100644
--- a/web/pgadmin/misc/__init__.py
+++ b/web/pgadmin/misc/__init__.py
@@ -0,0 +1,25 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2015, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module providing utility functions for the application."""
+MODULE_NAME = 'misc'
+
+from pgadmin.utils import PgAdminModule
+
+# Initialise the module
+blueprint = PgAdminModule(MODULE_NAME, __name__,
+                          url_prefix='')
+
+##########################################################################
+# A special URL used to "ping" the server
+##########################################################################
+@blueprint.route("/ping")
+def ping():
+    """Generate a "PING" response to indicate that the server is alive."""
+    return "PING"
diff --git a/web/pgadmin/misc/views.py b/web/pgadmin/misc/views.py
deleted file mode 100644
index 9b166b2..0000000
--- a/web/pgadmin/misc/views.py
+++ /dev/null
@@ -1,27 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module providing utility functions for the application."""
-MODULE_NAME = 'misc'
-
-import config
-from flask import Blueprint, render_template
-from flask.ext.security import login_required
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='')
-
-##########################################################################
-# A special URL used to "ping" the server
-##########################################################################
-@blueprint.route("/ping")
-def ping():
-    """Generate a "PING" response to indicate that the server is alive."""
-    return "PING"
-
diff --git a/web/pgadmin/redirects/__init__.py b/web/pgadmin/redirects/__init__.py
index e69de29..31c6fe5 100644
--- a/web/pgadmin/redirects/__init__.py
+++ b/web/pgadmin/redirects/__init__.py
@@ -0,0 +1,19 @@
+from pgadmin import PgAdminModule
+from flask.ext.security import login_required
+from flask import redirect, url_for
+
+MODULE_NAME = 'redirects'
+
+blueprint = PgAdminModule(MODULE_NAME, __name__,
+                          url_prefix='/')
+
+@blueprint.route('/')
+@login_required
+def index():
+    """Redirect users hitting the root to the browser"""
+    return redirect(url_for('browser.index'))
+
+@blueprint.route('/favicon.ico')
+def favicon():
+    """Redirect to the favicon"""
+    return redirect(url_for('static', filename='favicon.ico'))
diff --git a/web/pgadmin/redirects/views.py b/web/pgadmin/redirects/views.py
deleted file mode 100644
index ee323c9..0000000
--- a/web/pgadmin/redirects/views.py
+++ /dev/null
@@ -1,29 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module providing URL redirects."""
-MODULE_NAME = 'redirects'
-
-import config
-from flask import Blueprint, redirect, url_for
-from flask.ext.security import login_required
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__)
-
-@blueprint.route('/')
-@login_required
-def index():
-    """Redirect users hitting the root to the browser"""
-    return redirect(url_for('browser.index'))
-
-@blueprint.route('/favicon.ico')
-def favicon():
-    """Redirect to the favicon"""
-    return redirect(url_for('static', filename='favicon.ico'))
diff --git a/web/pgadmin/settings/__init__.py b/web/pgadmin/settings/__init__.py
index fb9f1a6..e96f50e 100644
--- a/web/pgadmin/settings/__init__.py
+++ b/web/pgadmin/settings/__init__.py
@@ -14,20 +14,95 @@ from flask.ext.login import current_user
 from flask.ext.sqlalchemy import SQLAlchemy
 
 from settings_model import db, Setting
+import traceback
+from flask import Blueprint, Response, abort, request, render_template
+from flask.ext.security import login_required
+
+import config
+from pgadmin.utils.ajax import make_json_response
+from pgadmin.utils import PgAdminModule
+
+MODULE_NAME = 'settings'
 
 def store_setting(setting, value):
     """Set a configuration setting for the current user."""
     data = Setting(user_id=current_user.id, setting=setting, value=value)
-    
+
     db.session.merge(data)
     db.session.commit()
-    
+
 def get_setting(setting, default=None):
-    """Retrieve a configuration setting for the current user, or return the 
+    """Retrieve a configuration setting for the current user, or return the
     default value specified by the caller."""
     data = Setting.query.filter_by(user_id=current_user.id, setting=setting).first()
-    
+
     if not data or data.value is None:
         return default
     else:
-        return data.value
\ No newline at end of file
+        return data.value
+
+# Initialise the module
+blueprint = PgAdminModule(MODULE_NAME, __name__, template_folder='templates', url_prefix='/' + MODULE_NAME)
+
+@blueprint.route("/settings.js")
+@login_required
+def script():
+    """Render the required Javascript"""
+    return Response(response=render_template("settings/settings.js"),
+                    status=200,
+                    mimetype="application/javascript")
+
+@blueprint.route("/store", methods=['POST'])
+@blueprint.route("/store/<setting>/<value>", methods=['GET'])
+@login_required
+def store(setting=None, value=None):
+    """Store a configuration setting, or if this is a POST request and a
+    count value is present, store multiple settings at once."""
+    success = 1
+    errorcode = 0
+    errormsg = ''
+
+    try:
+        if request.method == 'POST':
+            if 'count' in request.form:
+                for x in range(int(request.form['count'])):
+                    store_setting(request.form['setting%d' % (x+1)], request.form['value%d' % (x+1)])
+            else:
+                store_setting(request.form['setting'], request.form['value'])
+        else:
+            store_setting(setting, value)
+    except Exception as e:
+        success = 0
+        errormsg = e.message
+
+    return make_json_response(success=success,
+                              errormsg=errormsg,
+                              info=traceback.format_exc(),
+                              result=request.form)
+
+@blueprint.route("/get", methods=['POST'])
+@blueprint.route("/get/<setting>", methods=['GET'])
+@blueprint.route("/get/<setting>/<default>", methods=['GET'])
+@login_required
+def get(setting=None, default=None):
+    """Get a configuration setting."""
+    if request.method == 'POST':
+        setting = request.form['setting']
+        default = request.form['default']
+
+    success = 1
+    errorcode = 0
+    errormsg = ''
+
+    try:
+        value = get_setting(setting, default)
+    except Exception as e:
+        success = 0
+        errormsg = e.message
+
+    return make_json_response(success=success,
+                              errormsg=errormsg,
+                              info=traceback.format_exc(),
+                              result=request.form)
+
+
diff --git a/web/pgadmin/settings/settings_model.py b/web/pgadmin/settings/settings_model.py
index 731137b..3772728 100644
--- a/web/pgadmin/settings/settings_model.py
+++ b/web/pgadmin/settings/settings_model.py
@@ -9,7 +9,7 @@
 
 """Defines the models for the configuration database.
 
-If any of the models are updated, you (yes, you, the developer) MUST do two 
+If any of the models are updated, you (yes, you, the developer) MUST do two
 things:
 
 1) Increment SETTINGS_SCHEMA_VERSION in config.py
@@ -28,12 +28,13 @@ roles_users = db.Table('roles_users',
         db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
         db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
 
+
 class Version(db.Model):
     """Version numbers for reference/upgrade purposes"""
     __tablename__ = 'version'
     name = db.Column(db.String(32), primary_key=True)
     value = db.Column(db.Integer(), nullable=False)
-    
+
 class Role(db.Model, RoleMixin):
     """Define a security role"""
     __tablename__ = 'role'
@@ -51,7 +52,7 @@ class User(db.Model, UserMixin):
     confirmed_at = db.Column(db.DateTime())
     roles = db.relationship('Role', secondary=roles_users,
                             backref=db.backref('users', lazy='dynamic'))
-    
+
 class Setting(db.Model):
     """Define a setting object"""
     __tablename__ = 'setting'
@@ -64,21 +65,37 @@ class ServerGroup(db.Model):
     __tablename__ = 'servergroup'
     id = db.Column(db.Integer, primary_key=True)
     user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
+
     name = db.Column(db.String(128), nullable=False)
     __table_args__ = (db.UniqueConstraint('user_id', 'name'),)
-    
+
 
 class Server(db.Model):
     """Define a registered Postgres server"""
     __tablename__ = 'server'
     id = db.Column(db.Integer, primary_key=True)
-    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
-    servergroup_id = db.Column(db.Integer, db.ForeignKey('servergroup.id'), nullable=False)
+    user_id = db.Column(
+            db.Integer,
+            db.ForeignKey('user.id'),
+            nullable=False
+            )
+    servergroup_id = db.Column(
+            db.Integer,
+            db.ForeignKey('servergroup.id'),
+            nullable=False
+            )
+
     name = db.Column(db.String(128), nullable=False)
     host = db.Column(db.String(128), nullable=False)
-    port = db.Column(db.Integer(), db.CheckConstraint('port >= 1024 AND port <= 65534'), nullable=False)
+    port = db.Column(
+            db.Integer(),
+            db.CheckConstraint('port >= 1024 AND port <= 65534'),
+            nullable=False)
     maintenance_db = db.Column(db.String(64), nullable=False)
     username = db.Column(db.String(64), nullable=False)
-    ssl_mode = db.Column(db.String(16), nullable=False)
-    
-    
+    ssl_mode = db.Column(
+        db.String(16),
+        db.CheckConstraint(
+            "ssl_mode IN ('allow', 'prefer', 'require', 'disable', 'verify-ca', 'verify-full')"
+        ),
+        nullable=False)
diff --git a/web/pgadmin/settings/views.py b/web/pgadmin/settings/views.py
deleted file mode 100644
index 67e0d5a..0000000
--- a/web/pgadmin/settings/views.py
+++ /dev/null
@@ -1,83 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Views for setting and storing configuration options."""
-MODULE_NAME = 'settings'
-
-import traceback
-from flask import Blueprint, Response, abort, request, render_template
-from flask.ext.security import login_required
-
-import config
-from pgadmin.utils.ajax import make_json_response
-from . import get_setting, store_setting
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, template_folder='templates', url_prefix='/' + MODULE_NAME)
-
-@blueprint.route("/settings.js")
-@login_required
-def script():
-    """Render the required Javascript"""
-    return Response(response=render_template("settings/settings.js"),
-                    status=200,
-                    mimetype="application/javascript")
-    
-@blueprint.route("/store", methods=['POST'])
-@blueprint.route("/store/<setting>/<value>", methods=['GET'])
-@login_required
-def store(setting=None, value=None):
-    """Store a configuration setting, or if this is a POST request and a  
-    count value is present, store multiple settings at once."""
-    success = 1
-    errorcode = 0
-    errormsg = ''
-    
-    try:
-        if request.method == 'POST':
-            if 'count' in request.form:
-                for x in range(int(request.form['count'])):
-                    store_setting(request.form['setting%d' % (x+1)], request.form['value%d' % (x+1)])
-            else:
-                store_setting(request.form['setting'], request.form['value'])
-        else:
-            store_setting(setting, value)
-    except Exception as e:
-        success = 0
-        errormsg = e.message
-        
-    return make_json_response(success=success, 
-                              errormsg=errormsg, 
-                              info=traceback.format_exc(), 
-                              result=request.form)
-
-@blueprint.route("/get", methods=['POST'])
-@blueprint.route("/get/<setting>", methods=['GET'])
-@blueprint.route("/get/<setting>/<default>", methods=['GET'])
-@login_required
-def get(setting=None, default=None):
-    """Get a configuration setting."""
-    if request.method == 'POST':
-        setting = request.form['setting']
-        default = request.form['default']
-    
-    success = 1
-    errorcode = 0
-    errormsg = ''
-    
-    try:
-        value = get_setting(setting, default)
-    except Exception as e:
-        success = 0
-        errormsg = e.message
-
-    return make_json_response(success=success, 
-                              errormsg=errormsg, 
-                              info=traceback.format_exc(), 
-                              result=request.form)
diff --git a/web/pgadmin/templates/base.html b/web/pgadmin/templates/base.html
index 19cc511..300e888 100755
--- a/web/pgadmin/templates/base.html
+++ b/web/pgadmin/templates/base.html
@@ -15,28 +15,26 @@
         <meta name="dcterms.dateCopyrighted" content="2014 - 2015">
 
         <!-- Base template stylesheets -->
-        {% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.css') }}" />{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" />{% endif %}
-        {% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/alertify.css') }}" />{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/alertify.min.css') }}" />{% endif %}
-        {% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.css') }}" />{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.min.css') }}" />{% endif %}
-        {% if config.DEBUG %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">{% else %}<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css') }}">{% endif %}
-        <link rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css') }}">
-        {% if stylesheets is defined %}
+        <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.css' if config.DEBUG else 'css/bootstrap.min.css')}}"/>
+        <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/alertify.css' if config.DEBUG else 'css/alertifyjs/alertify.min.css') }}" />
+        <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/alertifyjs/themes/bootstrap.css' if config.DEBUG else 'css/alertifyjs/themes/bootstrap.min.css') }}" />
+        <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-theme.min.css' if config.DEBUG else 'css/bootstrap-theme.css') }}">
+        <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css') }}">
         <!-- View specified stylesheets -->
-        {% for stylesheet in stylesheets %}
-        <link rel="stylesheet" href="{{ stylesheet }}">{% endfor %}
-        {% endif %}
-        
+        {% for stylesheet in current_app.stylesheets %}
+        <link type="text/css" rel="stylesheet" href="{{ stylesheet }}">
+        {% endfor %}
         <!-- Base template scripts -->
-        <script src="{{ url_for('static', filename='js/modernizr-2.6.2-respond-1.1.0.min.js') }}"></script>
-        {% if config.DEBUG %}<script src="{{ url_for('static', filename='js/jquery-1.11.2.js') }}">{% else %}<script src="{{ url_for('static', filename='js/jquery-1.11.2.min.js') }}">{% endif %}</script>
-        {% if config.DEBUG %}<script src="{{ url_for('static', filename='js/bootstrap.js') }}">{% else %}<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}">{% endif %}</script>
-        {% if config.DEBUG %}<script src="{{ url_for('static', filename='js/alertifyjs/alertify.js') }}">{% else %}<script src="{{ url_for('static', filename='js/alertifyjs/alertify.min.js') }}">{% endif %}</script>
-        <script src="{{ url_for('static', filename='js/alertifyjs/pgadmin.defaults.js') }}"></script>
-        {% if scripts is defined %}
+        <script type="text/javascript" src="{{ url_for('static', filename='js/modernizr-2.6.2-respond-1.1.0.min.js') }}"></script>
+        <script type="text/javascript" src="{{ url_for('static', filename='js/jquery-1.11.2.js' if config.DEBUG else 'js/jquery-1.11.2.min.js') }}"></script>
+        <script type="text/javascript" src="{{ url_for('static', filename='js/bootstrap.js' if config.DEBUG else 'js/bootstrap.min.js') }}"></script>
+        <script type="text/javascript" src="{{ url_for('static', filename='js/alertifyjs/alertify.js' if config.DEBUG else 'js/alertifyjs/alertify.min.js') }}"></script>
+        <script type="text/javascript" src="{{ url_for('static', filename='js/alertifyjs/pgadmin.defaults.js') }}"></script>
         <!-- View specified scripts -->
-        {% for script in scripts %}
-        <script src="{{ script }}"></script>{% endfor %}
-        {% endif %}
+
+        {% for script in current_app.javascripts %}
+        <script type="text/javascript" src="{{ script }}"></script>
+        {% endfor %}
     </head>
     <body>
         <!--[if lt IE 7]>
diff --git a/web/pgadmin/test/__init__.py b/web/pgadmin/test/__init__.py
index e69de29..6ca55ef 100644
--- a/web/pgadmin/test/__init__.py
+++ b/web/pgadmin/test/__init__.py
@@ -0,0 +1,70 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2015, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Browser integration functions for the Test module."""
+MODULE_NAME = 'test'
+from flask.ext.security import login_required
+from flask import render_template, url_for
+from flask.ext.babel import gettext
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.menu import MenuItem
+from time import time, ctime
+
+class TestModule(PgAdminModule):
+
+    def get_own_menuitems(self):
+        return {'file_items': [
+            MenuItem(name='mnu_generate_test_html',
+                     label=gettext('Generated Test HTML'),
+                     priority=100,
+                     url=url_for('test.generated')),
+            MenuItem(name='mnu_test_alert',
+                     label=gettext('Test Alert'),
+                     priority=200,
+                     url='#',
+                     onclick='test_alert()'),
+            MenuItem(name='mnu_test_confirm',
+                     label=gettext('Test Confirm'),
+                     priority=300,
+                     url='#',
+                     onclick='test_confirm()'),
+            MenuItem(name='mnu_test_dialog',
+                     label=gettext('Test Dialog'),
+                     priority=400,
+                     url='#',
+                     onclick='test_dialog()'),
+            MenuItem(name='mnu_test_prompt',
+                     label=gettext('Test Prompt'),
+                     priority=500,
+                     url='#',
+                     onclick='test_prompt()'),
+            MenuItem(name='mnu_test_notifier',
+                     label=gettext('Test Notifier'),
+                     priority=600,
+                     url='#',
+                     onclick='test_notifier()')
+        ]}
+
+    def get_own_javascripts(self):
+        return [ url_for('test.static', filename='js/test.js') ]
+
+# Initialise the module
+blueprint = TestModule(MODULE_NAME, __name__)
+
+@blueprint.route("/generated")
+@login_required
+def generated():
+    """Generate a simple test page to demonstrate that output can be rendered."""
+    output = """
+Today is <b>%s</b>
+<br />
+<i>This is Flask-generated HTML.</i>
+<br /><br />
+<a href="http://www.pgadmin.org/">%s v%s</a>""" % (ctime(time()), config.APP_NAME, config.APP_VERSION)
+    return output
diff --git a/web/pgadmin/test/hooks.py b/web/pgadmin/test/hooks.py
deleted file mode 100644
index ba8f9a8..0000000
--- a/web/pgadmin/test/hooks.py
+++ /dev/null
@@ -1,29 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""Browser integration functions for the Test module."""
-
-from flask import render_template, url_for
-from flask.ext.babel import gettext
-
-def get_file_menu_items():
-    """Return a (set) of dicts of file menu items, with name, priority, URL, 
-    target and onclick code."""
-    return [
-            {'name': 'mnu_generate_test_html', 'label': gettext('Generated Test HTML'), 'priority': 100, 'url': url_for('test.generated')},
-            {'name': 'mnu_test_alert', 'label': gettext('Test Alert'), 'priority': 200, 'url': '#', 'onclick': 'test_alert()'},
-            {'name': 'mnu_test_confirm', 'label': gettext('Test Confirm'), 'priority': 300, 'url': '#', 'onclick': 'test_confirm()'},
-            {'name': 'mnu_test_dialog', 'label': gettext('Test Dialog'), 'priority': 400, 'url': '#', 'onclick': 'test_dialog()'},
-            {'name': 'mnu_test_prompt', 'label': gettext('Test Prompt'), 'priority': 500, 'url': '#', 'onclick': 'test_prompt()'},
-            {'name': 'mnu_test_notifier', 'label': gettext('Test Notifier'), 'priority': 600, 'url': '#', 'onclick': 'test_notifier()'},
-           ]
-    
-def get_scripts():
-    """Return a list of script URLs to include in the rendered page header"""
-    return [ url_for('test.static', filename='js/test.js') ]
\ No newline at end of file
diff --git a/web/pgadmin/test/views.py b/web/pgadmin/test/views.py
deleted file mode 100644
index 01088d5..0000000
--- a/web/pgadmin/test/views.py
+++ /dev/null
@@ -1,35 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2015, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module providing utility functions for the application."""
-MODULE_NAME = 'test'
-
-import config
-from flask import Blueprint, render_template
-from flask.ext.security import login_required
-from time import time, ctime
-
-# Initialise the module
-blueprint = Blueprint(MODULE_NAME, __name__, static_folder='static', template_folder='templates', url_prefix='/' + MODULE_NAME)
-
-##########################################################################
-# A test page
-##########################################################################
-@blueprint.route("/generated")
-@login_required
-def generated():
-    """Generate a simple test page to demonstrate that output can be rendered."""
-    output = """
-Today is <b>%s</b>
-<br />
-<i>This is Flask-generated HTML.</i>
-<br /><br />
-<a href="http://www.pgadmin.org/">%s v%s</a>""" % (ctime(time()), config.APP_NAME, config.APP_VERSION)
-
-    return output
diff --git a/web/pgadmin/utils/__init__.py b/web/pgadmin/utils/__init__.py
index e69de29..9370136 100644
--- a/web/pgadmin/utils/__init__.py
+++ b/web/pgadmin/utils/__init__.py
@@ -0,0 +1,87 @@
+from flask import Blueprint
+from collections import defaultdict
+from operator import attrgetter
+import sys
+
+
+
+class PgAdminModule(Blueprint):
+    """
+    Base class for every PgAdmin Module.
+
+    This class defines a set of method and attributes that
+    every module should implement.
+    """
+
+    def __init__(self, name, import_name, **kwargs):
+        kwargs.setdefault('url_prefix', '/' + name)
+        kwargs.setdefault('template_folder', 'templates')
+        kwargs.setdefault('static_folder', 'static')
+        self.submodules = []
+        super(PgAdminModule, self).__init__(name, import_name, **kwargs)
+
+    def register(self, app, options, first_registration=False):
+        """
+        Override the default register function to automagically register
+        sub-modules at once.
+        """
+        if first_registration:
+            self.submodules = list(app.find_submodules(self.import_name))
+        super(PgAdminModule, self).register(app, options, first_registration)
+        for module in self.submodules:
+            app.register_blueprint(module)
+
+    def get_own_stylesheets(self):
+        """
+        Returns:
+            list: the stylesheets used by this module, not including any
+                stylesheet needed by the submodules.
+        """
+        return []
+
+    def get_own_javascripts(self):
+        """
+        Returns:
+            list: the javascripts used by this module, not including
+                any script needed by the submodules.
+        """
+        return []
+
+    def get_own_menuitems(self):
+        """
+        Returns:
+            dict: the menuitems for this module, not including
+                any needed from the submodules.
+        """
+        return defaultdict(list)
+
+    def get_panels(self):
+        """
+        Returns:
+            list: a list of panel objects to add
+        """
+        return []
+
+    @property
+    def stylesheets(self):
+        stylesheets = self.get_own_stylesheets()
+        for module in self.submodules:
+            stylesheets.extend(module.stylesheets)
+        return stylesheets
+
+    @property
+    def javascripts(self):
+        javascripts = self.get_own_javascripts()
+        for module in self.submodules:
+            javascripts.extend(module.javascripts)
+        return javascripts
+
+    @property
+    def menu_items(self):
+        menu_items = self.get_own_menuitems()
+        for module in self.submodules:
+            for key, value in module.menu_items.items():
+                menu_items[key].extend(value)
+        menu_items = {key: sorted(values, key=attrgetter('priority'))
+                      for key, values in menu_items.items()}
+        return menu_items
diff --git a/web/pgadmin/utils/ajax.py b/web/pgadmin/utils/ajax.py
index 367c356..db77b97 100644
--- a/web/pgadmin/utils/ajax.py
+++ b/web/pgadmin/utils/ajax.py
@@ -9,20 +9,13 @@
 
 """Utility functions for dealing with AJAX."""
 
-from flask import Response
+from flask import jsonify
 import json
 
-def make_json_response(success=1, errormsg='', info='', result={}, data={}):
+def make_json_response(success=True, **kwargs):
     """Create a HTML response document describing the results of a request and
     containing the data."""
-    doc = { }
-    doc['success'] = success
-    doc['errormsg'] = errormsg
-    doc['info'] = info
-    doc['result'] = result
-    doc['data'] = data
-
-    response = Response(response=json.dumps(doc),
-                        status=200,
-                        mimetype="text/json")
-    return response
\ No newline at end of file
+    response = kwargs.copy()
+    response.setdefault('result', {})
+    response.setdefault('data', {})
+    return jsonify(response)
diff --git a/web/pgadmin/utils/menu.py b/web/pgadmin/utils/menu.py
new file mode 100644
index 0000000..e8628ba
--- /dev/null
+++ b/web/pgadmin/utils/menu.py
@@ -0,0 +1,27 @@
+from collections import namedtuple
+
+PRIORITY = 100
+
+class MenuItem(object):
+
+    def __init__(self, **kwargs):
+        self.__dict__.update(**kwargs)
+
+class Panel(object):
+
+    def __init__(self, name, title, content, width=500, height=600, isIframe=True,
+                 showTitle=True, isCloseable=True, isPrivate=False, priority=None):
+        self.name = name
+        self.title = title
+        self.content = content
+        self.width = width
+        self.height = height
+        self.isIfframe = isIframe
+        self.showTitle = showTitle
+        self.isCloseable = isCloseable
+        self.isPrivate = isPrivate
+        if priority is None:
+            global PRIORITY
+            PRIORITY += 100
+            priority = PRIORITY
+        self.priority = priority
diff --git a/web/setup.py b/web/setup.py
index c7398f5..22fbf24 100644
--- a/web/setup.py
+++ b/web/setup.py
@@ -66,6 +66,19 @@ def do_setup():
         server_group = ServerGroup(user_id=user.id, name="Servers")
         db.session.merge(server_group)
 
+        # TODO:: Remove this server later
+        #        It is here to demo the server listing is workig in
+        #        browser tree.
+        server_group = ServerGroup.query.filter_by(name='Servers').first()
+
+        server = Server(
+                user_id=user.id, servergroup_id=server_group.id,
+                name='PostgreSQL 9.3', host='localhost', port=3930,
+                maintenance_db='postgres', username='asheshvashi',
+                ssl_mode='prefer'
+                )
+        db.session.merge(server)
+
         # Set the schema version
         version = Version(name='ConfigDB', value=config.SETTINGS_SCHEMA_VERSION)
         db.session.merge(version)
@@ -138,4 +151,4 @@ if os.path.isfile(config.SQLITE_PATH):
     do_upgrade()
 else:    
     print "The configuration database %s does not exist.\nEntering initial setup mode...\n" % config.SQLITE_PATH
-    do_setup()
\ No newline at end of file
+    do_setup()
